directed-acyclic-graph

2 개의 포스트

slack4분 읽기큐레이션 요약

더 나은 소프트웨어를 만들기

빌드가 60분씩 걸리면 코드 변경에 대한 피드백이 늦어져 개발 생산성이 크게 떨어진다. Slack은 Bazel과 전통적인 성능 최적화 원칙인 캐싱·병렬화를 결합해 빌드 시간을 개선했다. 핵심은 빌드를 명확한 입력·출력 단위의 그래프로 모델링하고, 재사용 가능하고 병렬 실행 가능한 작은 작업으로 나누는 것이다. ## 빌드를 방향성 비순환 그래프로 모델링 - 백엔드와 프런트엔드는 서로 독립적으로 개발·배포될 수 있으며, 각각 필요한 소스 파일에만 의존한다. - 빌드 구성 요소와 배포 산출물 사이의 의존성은 방향성 비순환 그래프(DAG)로 표현된다. - 특정 Python 파일이 변경되면 백엔드만 다시 빌드하고, TypeScript 파일 변경 때문에 백엔드까지 재빌드하지 않도록 의존성을 정확히 정의할 수 있다. - 그래프로 빌드를 표현하면 애플리케이션 코드와 동일하게 다음 최적화를 적용할 수 있다. - 이미 수행한 작업의 결과를 저장해 다시 계산하지 않기 - 여러 컴퓨팅 자원에 작업을 분산해 동시에 처리하기 ## 캐싱을 통한 불필요한 작업 제거 - 캐시는 입력값과 결과값을 연결해 동일한 입력에 대한 작업을 한 번만 수행하도록 한다. - 예를 들어 `factorial(n)`은 입력 `n`에 따라 결과가 항상 같으므로 `functools.cache`를 적용할 수 있다. - 빌드 캐싱이 올바르게 작동하려면 작업이 다음 조건을 만족해야 한다. - **Hermetic**: 명시적으로 전달된 입력만 사용해 결과를 생성해야 한다. - **Idempotent**: 동일한 입력에 대해 항상 동일한 결과를 내야 한다. - 캐시 성능은 전체 호출 중 캐시에서 결과를 가져오는 비율인 캐시 적중률(hit rate)에 좌우된다. ## 작업 단위를 작게 나눠 캐시 적중률 높이기 - 이미지 목록 전체와 변환 목록 전체를 입력으로 받는 `process_images()`에 캐시를 적용하면, 이미지 하나만 추가돼도 전체 입력이 바뀐 것으로 간주된다. - 이 방식은 캐시 키가 지나치게 크고 거칠어, 작은 변경에도 모든 작업을 처음부터 다시 수행해야 한다. - 대신 이미지 하나에 변환 하나를 적용하는 `process_image(image, transform)`처럼 더 작은 단위에 캐시를 적용할 수 있다. - 그러면 새로 추가되거나 변경된 이미지·변환 조합만 처리하고, 이미 계산한 조합은 캐시에서 재사용할 수 있다. - 상위 수준 API는 유지하면서 내부 작업 단위만 세분화하는 방식이 성능과 재사용성을 높인다. ## 병렬화를 통한 작업 분산 - 이미지 처리처럼 서로 독립적인 작업은 여러 CPU 코어나 프로세스, 네트워크상의 다른 컴퓨팅 노드로 분산할 수 있다. - 병렬 실행을 위해서는 다음 조건이 필요하다. - 작업의 입력과 출력이 명확하게 정의되어야 한다. - 입력과 출력을 스레드·프로세스·네트워크 경계 너머로 전달할 수 있어야 한다. - 작업이 어떤 순서로 완료되거나 실패할지 보장할 수 없으므로 결과 처리 규칙을 명확히 해야 한다. - 예시의 스레드 기반 구현은 이미지 결과가 입력 순서와 다르게 반환될 수 있다. - 결과 순서 보장 여부는 API 계약의 일부이며, 사용자가 허용할 수 있는 동작인지 사전에 결정해야 한다. ## 병렬화에서도 작업 단위의 크기가 중요 - 작업 수가 적고 각각의 작업이 너무 크면 사용 가능한 컴퓨팅 자원에 충분히 분산하지 못한다. - 반대로 작업을 지나치게 잘게 나누면 작업 전달·관리 오버헤드가 커질 수 있다. - 적절한 작업 크기와 개수의 균형은 문제마다 다르므로 API와 빌드 단위를 설계할 때 함께 고려해야 한다. - 캐싱과 병렬화 모두 입력·출력이 명확하고 독립적인 작은 작업 단위를 필요로 한다. ## Bazel 빌드로 원칙 확장 - Bazel은 빌드를 방향성 비순환 그래프 형태의 **타깃(target)** 으로 정의한다. - 각 타깃에는 다음 세 가지 핵심 요소가 있다. - 빌드 단계의 입력이 되는 의존 파일 - 빌드 단계가 생성하는 출력 파일 - 입력을 출력으로 변환하는 명령어 - 이러한 명시적 정의를 바탕으로 변경된 타깃만 다시 빌드하고, 결과를 캐시하며, 서로 독립적인 타깃을 병렬 실행할 수 있다. - 따라서 빌드 시스템의 성능 개선은 단순히 더 빠른 도구를 도입하는 문제가 아니라, 코드 성능 최적화와 마찬가지로 작업의 경계와 의존성을 설계하는 문제다. 빌드 시간을 줄이려면 먼저 의존성과 입출력을 명확히 정의하고, 변경 범위가 작은 작업 단위로 빌드를 나누는 것이 좋다. 그 위에 hermetic·idempotent한 작업을 캐시하고 독립 작업을 병렬화하면, 대규모 프로젝트에서도 불필요한 재빌드를 줄이고 개발자 피드백 속도를 높일 수 있다.

원문 읽기(새 탭에서 열림)
google원문

InstructPipe: 인간의 지시 (새 탭에서 열림)

InstructPipe는 사용자의 자연어 명령을 기반으로 머신러닝 워크플로우를 자동 생성하는 AI 비주얼 프로그래밍 어시스턴트입니다. 두 단계의 대규모 언어 모델(LLM) 프로세스와 코드 인터프리터를 활용해 복잡한 노드 선택 및 연결 과정을 자동화하며, 초보자가 백지상태에서 파이프라인을 구축할 때 겪는 진입 장벽을 대폭 낮췄습니다. 이를 통해 기술적 숙련도와 상관없이 누구나 창의적인 아이디어를 시각적인 ML 파이프라인으로 신속하게 구현할 수 있는 환경을 제공합니다. ### 효율적인 파이프라인 표현 방식 * 기존 비주얼 블록 시스템이 사용하는 장황한 JSON 형식을 '의사코드(Pseudocode)' 형태로 압축하여 처리 효율을 극대화했습니다. * 의사코드 방식을 통해 파이프라인 표현에 필요한 토큰 수를 기존 2,800개에서 123개 수준으로 약 95% 이상 절감하여 LLM의 연산 부담을 줄였습니다. * 각 의사코드는 노드의 고유 ID, 유형, 입출력 변수명, 매개변수 정보를 포함하는 간결한 문법으로 정의되어 LLM이 구조를 정확히 파악하도록 돕습니다. ### 2단계 LLM 기반 생성 프로세스 * **노드 선택기(Node Selector):** 수많은 노드 라이브러리 중 사용자의 명령과 관련된 후보 노드들만 1차적으로 필터링합니다. 이는 마치 라이브러리 문서의 요약본을 훑어보는 것과 같아 시스템의 정확도를 높입니다. * **코드 작성기(Code Writer):** 선택된 노드들의 상세 사양(데이터 타입, 입출력 구조, 연결 예시 등)을 바탕으로 실제 작동 가능한 의사코드를 작성합니다. 상세한 컨텍스트를 제공하여 노드 간의 유효한 연결을 보장합니다. * **코드 인터프리터(Code Interpreter):** 최종 생성된 의사코드를 해석하여 비주얼 블록 에디터에서 즉시 수정 및 실행이 가능한 시각적 노드 그래프로 렌더링합니다. ### 사용자 경험 및 기술적 효용 * 초보 사용자가 적절한 노드를 찾고 수동으로 연결하는 데 드는 학습 곡선과 시간을 획기적으로 단축하여 프로토타이핑 속도를 가속화합니다. * 사용자는 단순히 명령어를 입력하는 것만으로 멀티모달 파이프라인을 구축할 수 있으며, 생성된 결과물은 사용자가 직접 세부 조정할 수 있는 유연성을 가집니다. * LLM의 추론 능력과 비주얼 프로그래밍의 직관성을 결합하여, 복잡한 ML 설계를 인간과 AI의 협업 체계로 전환했다는 점에 의의가 있습니다. InstructPipe는 복잡한 AI 모델을 조합하여 서비스 프로토타입을 빠르게 만들어야 하는 기획자나 개발자에게 강력한 도구가 될 수 있습니다. 단순히 결과를 자동 생성하는 것에 그치지 않고, 생성된 결과물을 사용자가 시각적으로 직접 편집할 수 있는 '수정 가능한 자동화' 워크플로우를 채택할 것을 권장합니다.