Outsider's Dev Story

Stay Hungry. Stay Foolish. Don't Be Satisfied.
RetroTech 팟캐스트 44BITS 팟캐스트

CUE가 승리하는 방법

구성(Configuration) 복잡도의 저주에 이어서 번역할 글로 마찬가지로 Dagger 문서를 보다가 이글도 같이 추천해 주고 있어서 번역해보았다.(자세히 봐야 할 것 같아서 번역했는데 여전히 어렵다.)

원글인 How CUE Wins은 2021년 5월에 작성된 글로 글의 저자인 LinkedIN의 SRE인 Cedric Charly허락받고 번역한 글이다.

CUE가 승리하는 방법

상당히 많은 구성 언어가 있지만 놀랍게도 단 하나도 범용적으로 쓰이는 언어가 되지는 못했다. 이유가 무엇일까? 어떤 사람은 손으로 직접 데이터 구조를 작성하는 것이 그렇게 어려운 일은 아니라고 생각한다. 모든 것을 JSON으로 구성해서 일을 처리하면 왜 안 되는 걸까? JSON이 작업에 충분한 추상화를 제공하지 못한다면 Python같은 범용 프로그래밍 언어를 사용하지 않는 이유는 무엇일까? 이 업계는 만족스러우면서 계속 발전하는 해결책을 표준화하는 데 실패했고 이는 노력 부족 때문이 아니다.

CUE에 관해 구성(Configuration) 복잡도의 저주라는 글을 쓰면서 그 대답을 준비했었지만 CUE같은 데이터 구성 언어(DCL, data configuration language)가 왜 더 빨리 성공하지 못했는지 알고 싶었다. 최근까지 대부분의 조직은 작업할 때 복잡한 구성이 크게 필요치 않았다. 예외가 있겠지만(CUE의 설계는 인간의 언어를 거대한 구성으로 정의한 계산 언어학(computational linguistics)에서 왔다.) 클라우드 컴퓨팅이 떠오르면서 복잡한 구성을 관리할 필요성도 더 많아졌다. 인프라스트럭처 구성을 위해 더 좋은 워크플로우에 관심과 욕구가 생기고 있다는 걸 알게 되어 Kubernetes나 Terraform 같은 클라우드 도구로 작업할 때도 의도적으로 CUE를 사용했다.

구성 언어로써의 성공은 튜링 완전성 없이 프로그래밍 언어의 문법을 단순히 복사한 것 이상의 의미를 가진다. 이전 이터레이션에서는 원칙을 지키려는 시도 안에 개발자가 제한하면서도 상응하는 혜택을 돌려주지 못했다. 새로운 언어가 이 새로운 환경의 공백을 채울 수 있다. 지금은 거의 모든 조직이 복잡한 구성과 씨름해야 하므로 업계 전반에 걸친 도전과 규모를 CUE가 맞출 수 있게 되었다. 결정적으로 CUE는 여전히 원칙을 지키고 있다. 구성은 튜링 완전하지 않아야 한다! 언어 개발은 트레이드 오프의 연속이다. 쿼리 엔진이나 쉬운 코드 생성/수정 같은 강력한 CUE 기능은 재귀를 허용하지 않음으로써 더 성장할 수 있다. 무엇보다 더 안전한 언어를 만들기 위한 좋은 선택이다.

장기적으로 CUE는 널리 퍼지게 되면서(ubiquity) 승리한다. 널리 사용되고 통합되는 구성 언어는 (영감을 받은) 구성 복잡성 시계를 해결하는 것이 핵심이다. 이 구성 복잡성 시계는 하드 코딩된 값으로 애플리케이션 구성을 관리하다가 성숙한 DSL(Domain Specific Language)로 바꾸었다가 결국 커스텀 DSL이 거추장스럽게 되어 하드 코딩된 값으로 돌아오는 순환을 설명한다. 비록 구성에는 DSL이 더 적합하지만, 디버깅, 도구, 라이브러리 같은 주변 컨텍스트가 부족하기 때문에 개발자는 지원되는 언어의 장점을 누리기 위해 하드 코딩으로 다시 돌아가게 되었다. 다시 말하지만, 언어를 만드는 것은 문법 이상의 작업이다. 오히려 워크플로우나 통합이 언어를 만들거나 깨뜨리게 된다. CUE가 구성 데이터 영역에서 작업을 가장 잘 다루기 때문에 미래에는 CUE가 새로운 기본값이 될 것이다.

공정히 말하자면 언어를 만드는 것이 간단한 작업은 아니다. 개발자가 어디서나 사용할 수 있는 유비쿼터스 언어(ubiquitous language)를 만드는 것은 훨씬 더 힘든 일이다. 하지만 CUE는 구성 언어이므로 가장 유리한 위치를 차지할 기회를 가진다. 이것이 주요 차이점인데 프로그래밍 언어가 고전적인 네트워크 효과라면 구성 언어는 시장(market)이다.

구성은 양면 시장이다

프로그래밍 언어는 여러 차원에서 네트워크 효과의 이점을 얻는다. 해당 언어의 사용자가 많으면 많을수록 좋은 라이브러리, 문서, 튜토리얼이 더 많이 생겨서 다시 더 많은 사용자를 끌어들인다. 한 조직인 일단 (개발 툴체인, 핵심 라이브러리 같은) 핵심 요구사항을 충족하면 이 조직은 꽤 상당히 독립적으로 된다. 이 조직은 원하는 소프트웨어를 구축할 수 있는 한 다른 사람이 하는 일을 신경 쓰지 않고 자기 일을 해낼 수 있게 된다.

반면에 구성은 그 자체로는 가치가 없다. 구성은 유용한 작업을 수행하는 프로그램에 구조화된 데이터를 공급하는 것이 목표이고 사용자와 소프트웨어 간의 계약이나 표준에 더 가깝다. 이것이 왜 중요할까? 구성 언어의 성공은 사용자와 도구 개발자 간의 시장을 만드는 것처럼 보인다. CUE 같은 언어를 사용하려는 이유로 사용자와 도구 개발자는 서로에게 접근을 원하게 된다.

  • 사용자는 여러 워크플로우에서 CUE를 사용할 수 있기를 원한다.(강력한 기능과 도구와 함께)
  • 도구 작성자는 구성 언어 지원을 정당화하기 위해 CUE 에 대한 높을 수요를 원한다.

문제는 지역 최댓값에 갇혀 있다는 것이다. 거의 모든 도구가 구성을 사용함에도 차별화 요소가 없기 때문에 대부분의 개발자는 YAML처럼 널리 알려지고 잘 지원되는 언어를 사용하기로 했다. 확대해 보면 이는 현대 소프트웨어 개발의 기초가 되지만 차별화되지는 않으면서 무거운 작업이다.

사용자 삽입 이미지

많은 개발자 도구가 비슷한 워크플로우를 가지지만 구성의 선택은 다양하다.


CUE는 양면 시장을 만들어야 한다. 하지만 각 면은 자체적인 규모의 경제를 가지고 있어서 이러한 그룹을 연결하는 것은 전통적인 닭과 달걀의 문제이기 때문에 양면 시장을 만드는 것은 네트워크 효과보다 어렵다. 몹시 어려운 일이다. 이 문제를 해결한 보답으로 이 양면 시장의 진입장벽이 CUE를 구성에서 진짜 지배자로 만드는 강력한 장벽이 되었다. 네트워크 효과가 있더라도 수많은 (가비지 컬렉트 vs 수동 메모리 관리 같은) 전문화와 여러 인기 있는 언어를 지원하는 업계의 독립성이 있다. 개발자가 하나의 도구에서 여러 복잡한 형식을 지원하길 원하지 않는 곳이나 같은 종류의 작업에 여러 고급 구성 언어를 배우려고 하지 않는 곳의 구성에서는 그 기회가 더 적다.

승리한 언어는 제곱의 법칙을 즐길 것이고 구성 통합, 라이브러리, 워크플로우에서 기본 선택이 되면서 널리 퍼지게(ubiquitous) 될 것이다. 다른 언어도 존재하겠지만 승리한 언어 같은 광범위한 지원이 없기 때문에 상대적으로 제한적이고 틈새시장이 될 것이다. 장벽이 해자(moat)가 된다.

롱테일 따라가기

시장을 만들 때 가장 어려운 부분을 엔진을 돌리고 다양한 행위자를 데려와야 한다는 것이다. CUE 사용자와 CUE 도구 제작자 중에서 초기 이득과 빠른 피드백을 위해 더 접근할 수 있는 쪽은 도구 제작자 쪽이다. 도구 제작자가 훨씬 작은 그룹이고 핵심 CUE 팀이 실질적인 도움을 크게 주고 있다. 또한 개발자는 복잡한 애플리케이션을 빈약한 구성 옵션으로 구축하는 것이 고통스럽다는 것을 예민하게 체감하고 현대적인 컴퓨팅 관리나 지속적 통합 시스템을 구축하려고 시도하면서 구성 옵션이 YAML/JSON이라는 것을 깨닫게 된다.(아마 너그럽다면 JSON 스키마를 사용할 것이다) 특정 시점에서 문제 영역의 복잡도는 더 고급 구성을 요구하게 된다. 이러한 요구를 받은 개발자는 CUE 통합을 통해 가장 큰 이점을 얻을 수 있다.

도구(Terraform, Kubernetes)와 다른 표준(YAML, Protocol Buffers)의 어댑터를 통합을 지원하는 것은 롱테일이다. 이는 언어에서 장기적인 작업으로 많이 진행되는 곳이지만 CUE를 성장시키는 가장 강력한 메커니즘이기도 하다. CUE를 효과적으로 도입한 대규모 프로젝트는 사용자를 CUE에 참여시킨다.

CUE는 이러한 모든 통합을 관리하는 데 장점을 가진다. 앞에서 얘기했듯이 구성은 애플리케이션 구성의 핵심이 아니다. 구성을 가져와서 사용하기 전에는 가장자리에 데이터로써 존재하게 된다. 이는 소프트웨어와 독립적으로 변경될 수 있다는 의미이다. 주어진 도구가 YAML/JSON을 입력으로 사용하고 있다면 CUE가 자동화를 통해 JSON으로 익스포트 할 수 있으므로 사용자는 CUE로 완전한 구성 워크플로우를 가질 수 있으며 소프트웨어를 익스포트 된 JSON과 동작하도록 수정할 필요도 없다. 이 CUE의 권한 없는 특징(permissonless)을 이용하면 프로젝트에 직접 작업하지 않고서도 서드파티가 CUE 라이브러리를 제공하는 것이 가능하다. Terraform, Cloudformation, Kubernetes, 다양한 CI 제품과 동작하는 라이브러리를 커뮤니티에서 만드는 것을 이미 알고 있다. 일단 CUE 패키지 관리를 시작하면 CUE 코드 공유는 더욱 시워지기 때문에 더 많은 라이브러리를 볼 수 있을 것이다.

클라우드 잡기

CUE가 모든 구성의 사용사례에서 잠재력을 가지기는 하지만 초기의 초점을 사용자 기반을 성장시킬 가능성이 높은 클라우드 컴퓨팅 같은 영역이어야 한다. 왜 특별히 클라우드일까? 클라우드 컴퓨팅은 아직도 상대적으로 새로우며 빠르게 성장하고 있고 선언적인 클라우드 구성을 사용하는 것은 더욱 최근의 일이다. 클라우드 컴퓨팅은 광범위한 수요가 있으면서 복잡한 구성이 요구되기 때문에 CUE에는 고유한 기회를 제공한다. 정기적으로 고급 구성을 사용하는 분야가 있지만 계산 언어 같은 분야는 틈새 시장인 반면 누구나 서버와 데이터베이스는 관리해야 한다.

인프라스트럭처를 관리하는 많은 프로젝트도 CUE를 기본 언어로 선택할 수 있는 영역이다. 이는 새로운 패러다임인 Infrastructure as Data(IaD)에 구성 언어가 훨씬 더 적합하기 때문이다. Kelsey Hightower는 여기여기에서 Infrastructure as Code(IaC)와 IaD를 비교했다. 핵심은 분석, 조작, 직렬화, 전송에 있어서 코드보다 데이터가 더 간단하다는 것이다. 목표는 데이터 구조를 모델링하고 관리하는 가장 효과적인 방법을 찾는 것이다.

물론 이에 대한 답은 구성 언어이지만 튜링 완전하지 않으므로 결코 더 나은 선택이 아니다. 이 글의 도입부로 돌아가서 복잡한 구성에 Python 같은 언어를 표준으로 선택하지 않는 이유는 무엇인가? 물론 프로그래밍 언어에는 패키지 관리자와 린터같은 도구뿐 아니라 다양한 형식과 프로토콜을 지원하는 커다란 커뮤니티와 다양한 라이브러리가 있다는 장점이 있다.

CUE를 지지하는 (저평가되었다고 생각하는) 주요 이유는 기회비용이다. 현대 프로그래밍 언어는 완전하고 통합된 툴 체인을 함께 제공하는 것이 당연하지만 아직 구성 언어에서는 이러한 기대를 할 수 없다. 놀랍게도 프로그래밍 언어보다 CUE가 오히려 고급 도구를 제공하기에 더 좋은 위치에 있다. 알려진 대로 CUE에서는 다른 언어에서 CUE로 혹은 그 반대로 코드를 생성하거나 추출하는 것이 훨씬 쉽다. 언어로서의 CUE는 코드 생성을 더 쉽게 할 뿐만 아니라 메타 코드 분석과 수정이 툴 체인에 구축되기 충분할 만큼 단순하다. 이러한 류의 장점은 쿼리 엔진cue vet, cue trim, cue fmt같은 리팩토링 도구에서 나타난다. Python 같은 언어로 이러한 기능이 가능할까? 하지만 CUE는 CUE의 제한된 특성으로 인해 제한된 언어 안에서 훨씬 쉽게 구현할 수 있게 되었고 핵심 언어 팀이 고급 기능과 워크플로우를 퍼스트 파티로 지원할 수 있기에 충분했다.

레이어 배치

사용자 삽입 이미지


CUE 컴포넌트 그림은 모든 부분이 어떻게 조합되는지 보여준다. 위 그림에서 핵심 엔진(Core Engine)과 DSL은 CUE의 언어로 생각되는 부분이다. 하지만 이는 개발자에게 언어를 제공하고 나머지는 알아서 만들도록 남겨둔 것이 아니다. CUE도 API와 cue 명령어에서 (코드 생성이나 변환 어댑터 같은) 주요 기능을 바로 노출한다. CUE 사용자가 사용할 수 있는 일부 강력한 기능이나 구성을 위해 CUE와 통합하는 다른 도구를 제공하려고 핵심 팀이 무거운 작업을 하는 것이 이 계층이라고 생각하면 된다.

시스템과 도구의 선언적인 인터페이스를 만들려는 개발자에게 진입 장벽을 엄청나게 낮추는 것이 최종 성과이다. 이는 고급 구성을 전문화된 기술에서 모든 개발자가 자신들의 도구에서 (새로운 기본값인) CUE를 지원할 수 있도록 분산하는 효과가 있다. 구성을 민주화하는 것은 도구의 롱테일을 지원하는데 핵심적인 부분이고 이는 CUE의 성장에 아주 중요하다.

CUE가 오픈소스이므로 구성을 분산화하는 것이 중요하다. 하지만 어디서나 사용되게 하려면 많은 행위자의 동의를 해야 하게 된다. 선언적 구성의 혜택을 받는 전 세계의 시스템과 워크플로우를 지원하는 것은 현실적이지 않다. 답은 개발자 레버리지를 제공하려고 프로젝트(또는 도구의 사용자)가 마찰이 별로 없이 독립적으로 지원할 수 있도록 CUE 통합을 아주 간단하게 만드는 것이다.

이것이 현재 최신 기술과 더 새로운 인프라스트럭처 관리 기술을 구분해 줄 것이다. Terraform과 Pulumi같은 도구는 기업의 후원을 집중적으로 받는다. 이는 모든 주요 클라우드를 모두 (여러 언어로) 코드 생성과 툴 체인을 만들어서 지원하는 것이 엄청난 노력이 들기 때문이다. 이들 덕분에 튼튼한 통합을 가진 오픈소스 프로젝트가 되었지만, 기업의 지원이 없다면 달성해야 하는 범위와 노력은 현실적으로 가능해 보이지 않는다.

집중화된 지원의 문제는 리소스가 유한하다는 것이다. 플러그인 시스템이 있다고 하더라도 시간이 흐르면서 통합을 만들고 유지보수하는 작업은 결코 사소한 일이 아니기 때문에 여러 언어에서 동작하도록 지원할 리소스를 가진 회사가 꼭 필요했다. 현 상황에서 크고 널리 지원되는 퍼블릭 클라우드에서는 사용하기 쉽지만 같은 기술의 혜택을 받을 수 있는 프라이빗 클라우드나 (작은 도구를 포함한) 커스텀 시스템에서는 어떨까? 더 나아가 선언적 인프라스트럭처의 정의가 더 큰 소프트웨어의 세계를 지원하도록 커진다면 어떻게 되겠는가?

협업적인 구성

사용자 삽입 이미지

유비쿼터스 구성 언어로 CUE를 사용하면 모든 개발자가 규모의 경제 혜택을 누릴 수 있다.


(소스 코드에서 자동 생성된) CUE 모듈이 최소한의 노력으로 시스템을 선언적으로 만들기에 충분할 것이므로 패키지 관리와 일부 커뮤니티에서 표준화된 자동화와 결합한 CUE는 기준을 충분히 낮출 것이다. 이는 모두가 선언적인 구성을 만들 수 있을 정도로 간단해질 때 중앙화된 협업 없이 독립적으로 이뤄질 수 있으므로 탈중앙화를 만드는 핵심 요소이다.

흥미로운 부분은 규모의 경제가 시작될 때이다. 개발자 대부분은 같은 종류의 도구로 같은 종류의 구성을 작성하게 되었지만, 스키마와 템플릿을 공유할 수단이 부족했다. Terraform으로 AWS 로드 밸런서를 정의하는 가장 좋은 방법을 모든 사람이 개별적으로 찾아야 하는가? CUE에서 인프라스트럭처를 정의하는 표준적인 방법은 모든 개발자가 패키징해서 재사용할 수 있는 스키마이다. 조직 관점에서 보면 스키마를 재사용할 수 있도록 공유하는 문제가 존재하고 이는 오히려 정책에 더 가까워 보인다.(회사는 모든 팀이 보안/단순성에 대한 특정 표준을 따르기를 원한다) 통일화한 덕분에 개발자는 커뮤니티가 (Kubernetes, Terraform, Jenkins 등) 도구를 위해 만든 구성 라이브러리를 사용할 것이고 회사는 내부적으로 특정 정책을 강제하고 팀이 현장에서 사용하는 보일러 플레이트 대부분을 제거하기 위해 회사의 라이브러리를 계층화할 것이다.

개발자가 획일적이면서도 무거운 구성 작업 대부분에서 자유로워지는 것이 장기적인 목표이다. 현재 상황은 모든 개발자가 모든 프로젝트에서 동작하는 빌드 도구와 표준 라이브러리를 만드는 것과 비슷한 상황이다. 유비쿼터스 구성 언어는 오늘날 많은 중복을 피하려고 롱테일의 라이브러리와 통합할 것이다. 새로운 기본값은 업계의 모두가 혜택을 얻을 수 있는 고수준의 사용 사례에 집중할 수 있게 한다. 예를 들어 Git 저장소에서 선언적인 구성을 읽어 일부 온라인 시스템(Kubernetes에는 이미 존재한다)과 동기화하는 프레임워크는 일반적으로 많은 도구에 유용할 것이다. 또 다른 애플리케이션은 구성의 변경 사항을 분석해서 서비스 중단을 유발하는 롤 아웃을 방지하는 도구이다. 결국 복잡한 시스템은 프로덕션에 걸쳐 개발하고 관리할 수 있도록 베스트 프랙티스 라이브러리와 워크플로를 가진 구성 툴 체인과 함께 제공될 것이다.

언어를 만드는 것은 마라톤이다.

구성 복잡도의 저주는 극복할 수 있다. CUE는 널리 퍼지게 함으로써(ubiquity) 구성 시계(configration 시계)를 극복할 수 있게 하는 언어이다. 이는 구성의 기본 솔루션이 될 만큼 충분한 가치를 제공한다. 물론 이 목표를 달성하려면 언어, 도구, 문서, 커뮤니티를 만드는 고된 작업이 필요할 것이다. 앞에서 설명한 모든 계층은 기여자가 지속해서 영향을 미칠 수 있는 곳이다.

CUE를 배우고 사용하기 시장과 롱테일에 관한 얘기 외에도 CUE는 가장 기본적인 수준에서 구성에 실제로 가장 훌륭한 언어이다. 이 언어의 좋은 측면은 시작하기 쉽다는 것이다. CUE는 일반적인 JSON이나 YAML 파일의 유효성 검사에 사용되므로 일치하는 CUE 스키마와 cue vet이 있으면 이미 존재하는 구성의 유효성 검사도 할 수 있다. JSON 관리에 일반적인 문제는 몇몇 도구만으로는 다루기 어렵다는 것이다. 여러 프로젝트에 걸쳐 재사용할 수 있는 구성을 생각하면 문제는 훨씬 심각해진다. CUE에서는 개발자가 전체 조직에 가치를 줄 수 있는 라이브러리와 자동화를 구성할 수 있다.

구성 라이브러리 개발하기 도구의 롱테일을 따라가는 것은 CUE 성공의 핵심 부분이다. CUE가 다루어야 할 세계는 한 팀이 다룰 수 있는 것보다 훨씬 크고 방대하다. 감사하게도 복잡한 구성이 모든 종류의 개발자가 접근할 수 있도록 CUE는 코드 생성과 패키지 관리 같은 기본 기능을 제공한다. Kubernetes, Terraform, Jenkins, GitHub Actions, Packer 같은 시스템(특히 자신만의 도구)과 동작하는 라이브러리를 만들고 공유해서 더 큰 커뮤니티와 바로 함께할 수 있다. 주요 프로젝트에 대한 지원을 만드는 것은 도구를 사용하는 방법에 대한 베스트 프랙티스를 효과적으로 설정할 수 있다. 이것이 이러한 복잡한 시스템의 인터페이스를 만드는 가장 인체공학적인 방법이기 때문이다. 많은 똑똑한 팀이 이를 알아챘고 CUE를 퍼스트파티로 지원해서 처음부터 그들의 도구를 사용할 수 있도록 더 나은 인터페이스를 효과적으로 정의했다. 다음 논리적인 단계는 CUE 자체를 돕는 것이다.

CUE 코어 프로젝트에 기여하기 CUE는 불과 2년 만에 엄청나게 발전했지만 1.0에 도달하려면 해결해야 할 과제가 있다. CUE DSL과 엔진은 비전에서 꽤 야심 찬 프로젝트이며 프로그래밍 언어 개발자는 프로젝트에서 작업하기 흥미로운 문제를 찾아낼 것이다. 언어 자체 외에도 핵심 팀이 CUE를 개선하고 사람들이 실제로 작성하는 CUE 코드에 대해 언어의 변경 사항을 테스트할 수 있도록 CUE 모듈 전체를 테스트해주는 unity같은 중요한 프로젝트도 존재한다. CUE discussionsSlack에 참여해 봐라.

CUE의 참신함과 구성 언어의 역동성은 모든 개발자가 사용할 언어를 만들 기회를 준다. 프로그래머는 구성에 있어서 지역 최댓값에 갇혀 있게 되고 현 상황은 개발자가 오늘날 마주하는 도전에 다다르지 못했다. 하지만 상황을 더 좋게 만들기에 현재 해결책은 너무 파편화되어 있고 무기력하다. CUE는 유비쿼터스를 달성할 수 있고 미래에 우리가 어떻게 구성을 작업해야 하는지 재정의할 수 있는 적시에 적절한 프로젝트이다.

2022/06/12 20:54 2022/06/12 20:54