본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 06. 04. 01:07

한 번도 사용해 본 적 없는 언어인 Ballerina로 AI 서비스를 구축했습니다. 놀라웠던 점들을 소개합니다.

요약

새로운 프로그래밍 언어 Ballerina를 사용하여 AI 감정 분석 API를 구축한 경험담입니다. Ballerina는 네트워킹 기능을 언어 자체에 내장하여 복잡한 서비스 연결 작업을 단순화하는 특징이 있습니다.

핵심 포인트

  • Ballerina는 네트워킹 기능을 언어 구문에 내장함
  • 엔드포인트와 함수가 통합되어 라우팅이 매우 간결함
  • 화살표(->) 연산자를 통해 네트워크 호출을 로컬 호출과 명확히 구분
  • JSON 데이터를 타입이 지정된 레코드로 자동 매핑

몇 주 전, 저에게는 작은 작업이 하나 있었습니다. 고객 리뷰와 같은 텍스트를 입력받아 AI 모델로 전송하고, 그것이 긍정적인지, 부정적인지, 혹은 중립적인지를 판별하여 한 줄 요약과 함께 반환하는 API를 구축하는 것이었습니다.

만약 저에게 어떻게 만들 것인지 물었다면, 저는 아마도 "Express를 쓸 것 같아요. 아니면 Flask요."라고 대답했을 것입니다. 그것이 저의 편안한 영역(comfort zone)이기 때문입니다. 대신 저는 한 번도 만져본 적 없는 것을 시도했습니다. 바로 API를 구축하고 서비스를 연결하기 위해 WSO2에서 만든 오픈 소스 언어인 Ballerina입니다.

문법을 처음 봤을 때 솔직한 제 반응은 "이게 대체 뭐야?" 였습니다. 마치 Java와 Python이 만나 아이를 낳은 것 같은 모습이었죠. 하지만 오후가 끝날 무렵, 저는 작동하는 서비스를 갖게 되었고, 구축하는 과정 중간 어디쯤에서 이 언어가 존재하는지를 이해하게 되었습니다. 다음은 제 기억에 남는 부분입니다.

Ballerina가 해결하고자 하는 지루한 문제

백엔드 서비스를 몇 개 구축해 보고 나면 깨닫게 되는 사실이 있습니다. 코드의 대부분은 실제 로직이 아니라는 점입니다. 그것은 _배관 작업(plumbing)_입니다. 요청을 받고, JSON을 추출하고, 형식이 맞는지 확인하고, 다른 서비스를 호출하고, 실패를 처리하고, 응답 형식을 재구성하여 다시 보내는 과정이죠. "감정(sentiment)을 파악하라"는 흥미로운 부분은 단 두 줄뿐입니다. 나머지는 모두 연결 작업(wiring)입니다.

대부분의 언어에서 그 연결 작업은 라이브러리를 통해 덧붙여집니다. Ballerina의 전략은 네트워킹을 언어 자체에 내장하는 것입니다. 세 가지 요소가 그것이 실제로 무엇을 의미하는지 보여주었습니다.

1. 엔드포인트(endpoint)가 곧 함수다

Express에서는 app.post('/analyze', handler)라고 작성합니다. 즉, 경로(route)와 핸들러(handler)는 서로 연결되는 두 개의 별개 요소입니다. 하지만 Ballerina에서는 이들이 하나입니다:

resource function post analyze(AnalyzeRequest req) returns AnalysisResult|error {
    // ...
}

post라는 단어는 HTTP 동사(verb)입니다. analyze라는 이름은 경로(path)입니다. 따라서 이 한 줄이 곧 POST /analyze가 됩니다. 별도의 라우팅(routing) 없이, 제 코드의 형태가 곧 제 API의 형태가 됩니다. 그리고 저 AnalyzeRequest req는 무엇일까요? Ballerina는 들어오는 JSON을 타입이 지정된 레코드(typed record)로 자동으로 부어 넣어줍니다. 따라서 제 코드가 실행될 때쯤이면 이미 깨끗한 req.text를 가지고 있게 됩니다. 수동 파싱(manual parsing)이 필요 없습니다.

2. 사고방식을 바꾸는 작은 화살표 하나

AI를 호출하기 위해 저는 다음과 같은 요청을 보냅니다:

groqClient->post("/chat/completions", requestBody, headers);

화살표를 보세요 - 점(.)이 아니라 ->입니다. Ballerina에서 ->는 **네트워크 호출 (network calls)**을 위해 예약되어 있습니다. 로컬 작업에는 일반적인 점(.)을 사용하지만, 컴퓨터를 벗어나는 모든 것은 화살표를 사용합니다.

처음에는 이것이 단순한 기벽(quirk)이라고 생각했습니다. 그러다 깨달았습니다. 네트워크 호출은 로컬 호출과 _근본적으로 다르다_는 것을 말이죠. 네트워크 호출은 느릴 수 있고, 타임아웃(time out)이 발생할 수 있으며, 상대측 서버가 다운될 수도 있습니다. Ballerina는 이러한 위험을 구문(syntax) 자체에서 가시화하여, 당신이 경계를 넘고 있다는 사실을 잊지 않게 해줍니다. 이제 어디에나 있는 일반적인 점(.)들은 무언가를 숨기고 있는 것처럼 느껴집니다.

3. 실수로 무시할 수 없는 에러들

제 함수는 AnalysisResult|error를 반환합니다. 이 바(|)는 "결과 또는 에러"를 의미합니다. 에러는 옆으로 던져지는 것이 아니라, 타입(type) 안에 바로 자리 잡고 있는 일반적인 반환 값(return value)입니다.

그리고 호출 앞에는 작은 check가 붙어 있습니다:

GroqResponse groqResponse = check groqClient->post(...);

check의 의미는 다음과 같습니다: 이 작업을 수행하되, 만약 에러가 반환되면 여기서 멈추고 해당 에러를 상위로 전달하라. 이는 다섯 글자로 표현된 try/catch 댄스입니다 (만약 Rust의 ?나 Go의 err를 알고 있다면, 바로 그 개념입니다). 제 코드는 위에서 아래로 '해피 패스 (happy path)'로 읽히며, check는 모든 것을 어지럽히지 않고 조용히 실패를 처리합니다.

그래서 이것의 실제 용도는 무엇인가요?

이제 친구에게 Ballerina를 설명한다면 이렇게 말하겠습니다: 이것은 접착제 (glue)를 위한 것입니다. API와 데이터베이스를 호출하는 다른 요소들 사이에 앉아 데이터를 재구성하고 전달하는 것 자체가 임무인 서비스들 말이죠. 우리가 앱을 외부 API에 연결하고, 점점 더 많은 AI 모델에 연결함에 따라 계속해서 늘어나는 바로 그런 종류의 작업입니다.

저의 작은 피드백 분석기는 매우 실제적인 패턴의 작은 버전입니다. 즉, 지저분한 외부 세계가 오직 깔끔한 것만을 볼 수 있도록 언어 모델(language model) 앞에 깨끗하고 타입이 지정된 API를 두는 것이죠. Ballerina는 이 과정이 번거롭지 않고 자연스럽게 느껴지도록 만들어 주었습니다.

솔직한 초보자의 관점

모든 과정이 매끄럽기만 했던 것은 아닙니다. 구문 (syntax)을 익히는 데 시간이 조금 걸렸고, 문서 (docs)에 많이 의존했습니다. 아직 다뤄보지 못한 것들도 많습니다. 인메모리 저장소 (in-memory storage) 대신 실제 데이터베이스 (database)를 사용하는 것, 테스트 (tests), 재시도 (retries) 로직 등이 그렇습니다. 하지만 제 기억에 남는 핵심은, 제가 '어떻게 연결할지 (how to wire it up)'가 아니라 '무엇을 만들고 싶은지 (what I wanted to build)'를 고민하며 오후 시간을 보냈다는 점입니다. 무언가를 연결하기 위해 만들어진 언어로서, 이는 제가 줄 수 있는 최고의 찬사입니다.

만약 여러분이 평소에 "프레임워크를 임포트 (import)하고 그것들을 하나로 엮는" 방식으로 API를 구축해 왔다면, Ballerina는 여러분의 호기심을 위해 오후 시간 정도를 투자할 가치가 있습니다.

전체 프로젝트는 제 GitHub에 있습니다:
GitHub Repo
코드를 직접 살펴보고 싶으시다면 방문해 주세요.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
0

댓글

0