기술 글

AI가 코드를 작성하는 시대, Scala는 경쟁력이 있을까?

0 0

AI가 코드를 작성하는 비중이 빠르게 늘고 있다. 아직은 사람이 설계하고 AI가 구현을 보조하는 경우가 많지만, 코드의 상당 부분을 AI가 작성하는 방향으로 가고 있다는 것은 분명해 보인다.

그렇다면 프로그래밍 언어를 선택하는 기준도 달라질까?

Scala는 강한 타입 시스템과 함수형 프로그래밍, 높은 표현력을 가진 언어다. 사람이 코드를 작성할 때는 이런 특성이 장점인 동시에 Scala를 어렵게 만드는 이유이기도 했다. 하지만 AI가 코드를 작성한다면 이야기가 조금 달라질 수 있다. 사람이 작성하기 편한가보다 AI가 잘못 만든 코드를 컴파일러가 얼마나 잡아낼 수 있는가가 더 중요해질 수도 있기 때문이다.

처음에는 이런 이유로 Scala가 AI 시대에 의외의 기회를 얻을 수도 있다고 생각했다.

그러다 Kotlin이 떠올랐다.

Kotlin 역시 정적 타입 언어이고 null safety를 비롯한 실용적인 안전장치가 잘 갖춰져 있다. Java 생태계를 그대로 활용할 수 있고 Android, 서버, Multiplatform 등 사용 범위도 넓다. AI가 접할 수 있는 코드와 문서의 양에서도 Scala보다 유리하다.

이 문제를 Scala 커뮤니티에 던져봤다. 질문은 Scala와 Kotlin의 비교에서 시작했지만 이야기는 type system, training data, Rust, Lean, effect, capability까지 이어졌다.

AI가 코드를 쓴다면 강한 타입 시스템은 더 중요해질까

AI가 만든 코드가 처음부터 정확하다고 기대하기는 어렵다. 지금도 AI coding을 하다 보면 존재하지 않는 API를 사용하거나 타입을 잘못 이해하고, 프로젝트의 기존 설계와 맞지 않는 코드를 만드는 경우가 있다.

동적 언어나 타입 시스템이 약한 언어에서는 이런 코드 중 일부가 실행 단계까지 살아남는다. 정적 타입 시스템이 강해질수록 컴파일러가 잡아낼 수 있는 범위가 넓어진다.

AI가 코드를 생성하고 compiler error를 다시 받아 수정하는 과정까지 자동화한다면 이 차이는 더 중요해질 수 있다.

이 관점에서 Scala의 복잡한 타입 시스템은 단순히 언어를 어렵게 만드는 요소가 아니다. 프로그램이 만족해야 할 조건을 더 많이 타입으로 표현할 수 있다면 AI가 만들 수 있는 잘못된 프로그램의 범위도 줄일 수 있다.

물론 Scala의 표현력이 항상 장점으로 작용하는 것은 아니다.

Scala는 같은 문제를 표현하는 방법이 많다. FP library와 abstraction까지 사용하기 시작하면 상당히 복잡한 코드를 만들 수도 있다. AI에게 별다른 기준을 주지 않으면 사람이 보기에는 필요 이상으로 복잡한 코드를 만들어내기도 한다.

그래서 Scala에서 AI를 사용할 때는 무엇을 사용할지뿐 아니라 무엇을 사용하지 않을지도 중요하다. 프로젝트에서 허용할 abstraction과 coding pattern을 미리 정해놓는 방식이 필요해질 수 있다.

그렇다면 Kotlin은?

Kotlin도 충분히 type-safe하다. 일반적인 application 개발에서 필요한 null safety, generics, sealed type, smart cast 같은 기능도 잘 갖추고 있다.

하지만 Kotlin과 Scala가 지향하는 타입 시스템의 범위는 같지 않다.

Scala는 type class, higher-kinded type, union/intersection type, match type, contextual abstraction 등 타입 시스템을 프로그램 설계에 훨씬 적극적으로 사용할 수 있다. 최근에는 capture checking을 통해 값이나 함수가 어떤 capability를 포착하고 있는지까지 타입에서 추적하려는 작업이 진행되고 있다.

따라서 AI coding이라는 관점에서는 단순히 "둘 다 정적 타입 언어"라는 비교보다 컴파일러에게 얼마나 많은 제약을 표현할 수 있느냐가 더 중요한 차이가 될 수 있다.

생태계에서는 반대 방향의 힘이 작용한다.

Kotlin은 Scala보다 훨씬 넓은 영역에서 사용되고 Java 생태계와의 연결도 강하다. AI가 접할 수 있는 코드, 문서, library 사용 예제가 많다는 것은 무시하기 어려운 장점이다.

다만 Kotlin의 전체 생태계 규모가 곧바로 모든 영역에서 Scala에 대한 우위로 이어지는 것은 아니다.

예를 들어 두 언어가 직접 경쟁하는 backend에서는 Kotlin이 Spring을 비롯한 Java framework를 사용하는 경우가 많다. 반면 현재 Scala를 사용하는 프로젝트들은 Tapir, Smithy4s, ZIO 같은 Scala 고유의 stack을 깊게 사용하는 경우가 있다.

여기에서는 단순한 코드의 양보다 개발 방식의 차이가 중요해진다.

Schema와 type을 먼저 정의하고 그 제약 안에서 구현하는 schema-driven development는 AI coding과 꽤 잘 맞을 가능성이 있다. AI에게 프로그램 전체를 자유롭게 만들게 하는 것보다 먼저 가능한 프로그램의 형태를 좁혀놓는 방식이기 때문이다.

그런데 AI가 코딩한다면 더 극단적인 언어를 쓰면 되지 않을까

여기서 꽤 근본적인 반론이 나온다.

Scala는 오랫동안 일종의 middle ground에 있었다.

Java보다 강력한 타입 시스템과 높은 추상화 능력을 제공하면서도 일반적인 application을 만들 수 있다. Lean 같은 언어처럼 프로그램의 성질을 증명하는 데 초점을 맞춘 것도 아니고, Rust나 C처럼 시스템 프로그래밍과 성능을 중심으로 만들어진 언어도 아니다.

사람이 직접 코드를 작성하는 시대에는 이런 절충점이 의미가 있었다.

언어가 지나치게 엄격해지면 개발자가 감당해야 할 비용도 커지기 때문이다.

그런데 AI가 그 비용을 대신 부담한다면 상황이 달라질 수 있다.

정확성이 중요하다면 Lean처럼 더 강한 검증을 제공하는 언어를 사용하고, 성능과 memory safety가 중요하다면 Rust를 사용하면 되지 않을까. 사람이 직접 작성하기 어렵다는 문제가 AI로 상당 부분 해결된다면 굳이 그 사이에 있는 언어를 선택해야 할 이유가 줄어들 수도 있다.

Rust는 특히 이 관점에서 흥미롭다.

Ownership과 borrowing을 통해 memory safety와 data race를 컴파일 단계에서 강하게 통제하면서 GC 없이 높은 성능을 제공한다. 그동안 Rust의 높은 학습 비용과 작성 난도가 단점이었다면 AI가 코드를 작성하는 환경에서는 그 단점의 비중이 낮아질 수 있다.

AI가 Scala의 복잡성을 해결해주는 동시에 Rust의 복잡성도 해결해준다면 어느 쪽이 더 큰 이익을 얻을지는 생각해볼 문제다.

Scala의 또 다른 약점은 training data다

컴파일러가 강하다는 것과 AI가 그 언어의 코드를 잘 작성한다는 것은 다른 문제다.

Python이나 Java, JavaScript와 비교하면 공개된 Scala 코드와 문서, 예제의 양은 훨씬 적다. LLM이 Scala 자체는 알고 있더라도 최신 library의 idiom이나 특정 ecosystem의 사용법까지 얼마나 정확하게 이해하고 있는지는 별개의 문제다.

강한 compiler feedback이 부족한 training data를 어느 정도 보완할 수는 있다.

AI가 틀린 코드를 만들고 컴파일러가 거부하고, 그 오류를 바탕으로 다시 코드를 수정할 수 있기 때문이다.

하지만 처음 생성되는 코드의 품질 차이를 완전히 없애는지는 알 수 없다.

결국 AI coding에서는 두 가지 힘이 동시에 작용한다.

AI가 많이 학습해서 처음부터 좋은 코드를 만드는 언어가 유리할 수도 있고, AI가 잘못 만든 코드를 compiler가 강하게 거부하는 언어가 유리할 수도 있다.

모든 것을 증명할 필요는 없다

Scala가 Lean처럼 fully provable하지 않다는 지적에 대해서는 다른 방향에서 볼 수도 있다.

실제 application에서 프로그램 전체의 correctness를 수학적으로 증명해야 하는 경우는 많지 않다.

대신 몇 가지 중요한 속성을 확실하게 보장하는 것만으로도 상당한 가치가 있다.

특히 AI agent에서는 "이 코드의 모든 로직이 올바른가?"만큼이나 "이 코드가 해서는 안 되는 일을 할 수 있는가?"가 중요하다.

여기서 capability가 등장한다.

AI에게 파일을 삭제하지 말라고 하거나 기밀 데이터를 외부로 보내지 말라고 지시할 수 있다. 하지만 결국 모델이 지시를 제대로 따를 것이라는 가정이 필요하다.

Sandbox에서 권한을 제한할 수도 있다. 하지만 agent 전체에는 네트워크가 필요하면서 특정 데이터를 처리할 때만 네트워크 접근을 금지해야 하는 것처럼 더 세밀한 제어가 필요한 경우가 있다.

Capability를 타입 시스템에서 추적하면 문제를 다르게 접근할 수 있다.

어떤 computation이 데이터베이스를 사용할 수 있는지, 파일 시스템에 접근할 수 있는지, 외부 네트워크와 통신할 수 있는지를 코드의 구조와 타입을 통해 제한하는 것이다.

AI가 위험한 코드를 생성하지 않기를 기대하는 대신 위험한 행동에 필요한 capability를 가질 수 없도록 만드는 방식이다.

Tracked Capabilities for Safer Agents

이 방향은 단순한 가능성만 이야기되는 단계는 아니다.

Martin Odersky는 최근 "Tracked Capabilities for Safer Agents"에서 Scala의 capture checking을 AI agent의 안전성에 직접 적용하는 방법을 소개했다.

핵심은 모델을 신뢰하지 않는다는 데 있다.

Agent가 충분히 똑똑해서 실수하지 않기를 기대하거나 prompt를 통해 행동을 통제하는 대신, 모델이 어떤 코드를 만들어도 일정한 안전 조건을 벗어날 수 없도록 infrastructure에서 보장하자는 것이다.

예를 들어 agent가 기밀 문서를 읽고 요약해야 한다고 하자.

문서를 읽기 위해서는 해당 데이터에 접근할 수 있어야 하고 결과를 저장할 수도 있어야 한다. 동시에 원본 데이터를 외부 네트워크로 유출해서는 안 된다.

Tracked capability를 이용하면 기밀 데이터를 처리하는 특정 computation이 외부와 통신할 수 있는 capability를 가지지 못하도록 제한할 수 있다.

Agent 자체는 다른 작업에서 네트워크를 사용할 수 있다. 하지만 기밀 데이터에 접근하는 computation 안에서는 그 capability를 사용할 수 없다.

AI가 데이터를 외부로 보내는 코드를 만들어도 필요한 capability가 없다면 type check를 통과하지 못한다.

Odersky 연구팀은 이 아이디어를 TACIT이라는 agent harness로 구현했고 여러 모델과 benchmark를 이용해 실험했다. 연구에서 다룬 정보 유출 공격은 차단하면서 일반적인 task 수행 능력은 유지됐다고 보고하고 있다.

물론 아직 일반적인 해법이라고 보기는 어렵다.

Scala의 capture checking 자체가 여전히 experimental한 영역이고, 실제 대규모 시스템에서 어디까지 적용할 수 있을지도 더 검증되어야 한다.

그래도 한 가지는 분명하다.

Scala의 복잡한 타입 시스템이 AI 시대에 어떤 의미를 가질 수 있는지에 대해 꽤 구체적인 방향이 나오기 시작했다는 것이다.

Scala의 middle ground는 사라질까

결국 처음의 반론으로 돌아오게 된다.

AI가 코드를 작성한다면 인간을 위해 만들어진 middle ground가 필요 없어질까.

그럴 수도 있다.

AI가 프로그래밍의 작성 비용을 크게 낮춘다면 지금까지 사람이 다루기 어렵다는 이유로 선택하지 않았던 더 엄격한 언어를 사용할 수 있다. Rust가 대표적인 후보이고, 특정 영역에서는 Lean 같은 언어의 사용 범위가 넓어질 수도 있다.

반대로 대부분의 소프트웨어를 theorem prover나 system language로 작성할 이유도 없다.

일반적인 application을 만들 수 있으면서 type, schema, effect, capability를 통해 AI가 만들 수 있는 프로그램의 범위를 강하게 제한할 수 있다면 Scala의 middle ground는 사라지는 것이 아니라 의미가 달라질 수도 있다.

사람에게 충분히 강력하면서도 사용할 수 있는 언어였던 것이, AI에게 충분한 자유를 주면서도 위험한 프로그램을 만들지 못하게 하는 언어로 바뀌는 것이다.

아직 어느 쪽이 맞는지는 알기 어렵다.

Kotlin처럼 큰 생태계와 많은 training data를 가진 언어가 계속 유리할 수도 있다. Rust처럼 강한 compiler guarantee와 성능을 가진 언어가 AI의 도움으로 더 넓은 영역까지 올라올 수도 있다. Scala의 capability와 effect에 대한 접근이 실제 AI agent 개발에서 중요한 장점으로 자리 잡을 수도 있다.

다만 AI가 프로그래밍 언어의 차이를 없애줄 것이라는 생각은 조금 단순한 것 같다.

오히려 사람이 코드를 직접 작성하는 비중이 줄어들수록 언어에 요구하는 것이 달라질 가능성이 있다.

얼마나 쉽게 작성할 수 있는가보다 얼마나 많은 것을 컴파일러가 검증할 수 있는가.

그리고 AI가 잘못된 코드를 만들었을 때 그 코드가 할 수 있는 일을 어디까지 제한할 수 있는가.

AI 시대의 프로그래밍 언어 경쟁은 이쪽에서 다시 시작될지도 모르겠다.

참고

이 글을 쓰게 된 계기가 된 Reddit 토론
https://www.reddit.com/r/scala/comments/1vk2e1i/scala_vs_kotlin_in_the_age_of_aigenerated_code/

Martin Odersky, "Tracked Capabilities for Safer Agents"
https://martinodersky.substack.com/p/tracked-capabilities-for-safer-agents

Scala 3 Reference, Capture Checking
https://docs.scala-lang.org/scala3/reference/experimental/capture-checking/

"Securing Agents with Tracked Capabilities"
https://doi.org/10.1145/3786335.3813127

이 글은 Reddit의 Scala 커뮤니티에서 나눈 토론과 위 자료들을 바탕으로 정리했으며, 글을 작성하고 다듬는 과정에서 ChatGPT를 활용했습니다.

댓글 0

댓글을 불러오는 중입니다.