프로그래밍
프로그래밍 언어에 대한 농담과 논쟁은 세상의 존재만큼 오래되었죠. 그렇다면 어떤 언어를 선택해야 할까요? 선택하려면 어떻게 해야 할까요?
아마도 수백 가지의 프로그래밍 언어가 존재하며, 일부는 매우 인기가 많고 일부는 그렇지 않습니다. 이러한 이유로 (선택을 만드는 데) 정리하기가 어려울 수 있습니다. 이 기사에서는 어떻게 언어를 분류하고, 어떤 기준을 중요하게 생각하며 어떻게 선택을 하는지에 대해 설명하겠습니다.
실제로, 이 프로젝트는 사용할 언어에 대한 초기 필터링을 가능하게 하는 첫 번째 유형의 프로젝트입니다.
- 언어 카테고리
- 전문화된 언어
처음 다룰 언어 카테고리는 전문화된 언어입니다. 어떤 분야에서는 언어를 선택할 여지가 거의 없거나 전혀 없는 경우도 있습니다. 이들은 종종 매우 특정 분야에서 사용되는 언어들입니다.
예를 들어, 제가 공부하면서 실습할 기회가 있었던 VHDL은 이 카테고리에 속합니다. 이 언어는 하드웨어를 설명하는 데 사용되는 소수의 특화된 언어 중 하나입니다. 또한, 가끔 이 언어를 사용해 하드웨어와 놀고 싶어지기도 합니다. 정말 재미있는 언어거든요; 때로는 다시 뭔가 하드웨어를 사서 놀고 싶어지기도 해요.
간단히 말해서 이러한 언어들은 선택의 문제가 다른 곳보다 적게 발생하는 특정 영역을 가지고 있습니다.
수집자의 차고가 필요한가요?
만약 “주류” 언어들을 비교하려면, 첫 번째 중요한 기준은 가비지 컬렉터의 존재 여부입니다. 기억해두세요, 가비지 컬렉터 (GC)는 프로그램에서 메모리의 할당과 해제를 직접 관리하지 않고 가능하게 하는 구성 요소입니다.
이는 프로그램을 크게 단순화시킵니다 (우리는 나중에 이에 다시 언급하겠습니다) 그러나 메모리 소비와 성능 (특히 프로그램의 지연 시간에서)에서는 더 많은 비용을 초래합니다.
일부 매우 특정한 프로그램(커널, 실시간 등)은 가비지 컬렉터를 허용할 여유가 없을 수 있습니다. 우리가 가비지 컬렉터가 없는 언어에 대해 이야기할 때 일반적으로 비교하는 세 가지 언어는 C, C++, 그리고 Rust입니다.
이는 역사적인 언어입니다. 어디에서나(예: Linux 커널에서) 찾을 수 있어서 완전히 이곳 없이는 할 수 없다고 생각할 정도입니다. 비슷하게, C++은 많은 프로그램에서 발견되는 인기 있는 언어입니다.
이 두 언어의 문제는 개발자로부터 엄격함을 요구한다는 점입니다. 실제로, 메모리를 수동으로 관리하는 것은 어려우며, 버그가 빨리 나타날 수 있습니다. 이러한 종류의 버그는 공격자가 기계를 제어할 수 있게 할 수 있기 때문에 꽤 위험합니다.
Rust는 이 문제를 해결하기 위해 고안되었습니다: 가비지 컬렉터가 없는 언어로, 컴파일 시 메모리 관리 버그를 피하도록 합니다. Rust는 이것만 가져오는 것이 아닙니다(나중에 타이핑과 생태계에 대해 이야기할 것입니다), 하지만 이미 좋은 점입니다.
이 문서의 범위를 벗어나긴 하지만, 시스템 프로그래밍은 항상 접근하기 어려운 부분이라고 생각해왔어요. 매우 난해하고 이해하기 어려운 세세한 부분과 좋은 관행들이 가득해요 (그리고 OpenSSL 개발자들이 메모리 관련 버그를 도입했다면, 우리에게도 마찬가지일 것이라는 걸 바로 알 수 있죠). 전처리기에 기반한 불가해한 주문 같은 모호한 말들이 가득하며, Makefile에 박사 학위가 없다면 이해하기 어려운 빌드 프로세스와 의존성 설치가 얽혀 있어요. 요약하자면, Rust에 대해 어떻게 생각하든, 적어도 우리 같은 평범한 사람에게 시스템 프로그래밍을 접근 가능하게 만드는 것 같아서 좋아요.
그래서, Garbage Collector(GC)가 필요할까요?
내가 생각하기에는 97%의 프로그램(내가 예상한 숫자임)이 가비지 컬렉터를 허용할 수 있다고 생각해요. 가비지 컬렉터의 장점은 다음과 같아요:
- 개발 용이성: 예를 들어 Rust는 GC 없이 안전해질 때까지 거대한 비중(하지만 그 목표를 고려하면 정당화된 비중이에요)을 적용해요. 저는 간단하고 명료한 코드를 좋아하며, 개발하는 과정에서 편안함을 중요시해요.
- 대부분 어플리케이션은 GC를 허용할 수 있어요: 오늘날의 가비지 컬렉터들은 매우 효율적이에요. 최근에는 예를 들어 Java 가상 머신(JVM)의 ZGC에 대해 많은 이야기가 나왔어요. 가비지 컬렉터가 작동 중일 때 가끔 몇몇 쿼리가 조금 더 실행되는 데 걸리는 몇십 밀리초가 중요한지 생각해보세요. 대부분의 어플리케이션에게는 이것이 크리티컬한 문제가 아니에요.
물론, 수백 기가바이트에서 심지어 테라바이트까지 사용하는 프로그램을 관리하는 것은 도전입니다. 하지만 우리는 매우 구체적인 요구 사항을 해결하기 위해 여기 있고, ZGC와 같은 솔루션이 이러한 요구 사항에 적합할 수 있다는 것을 알 수 있습니다.
그래고 아무튼, GC가 있든 없든, 이러한 종류의 애플리케이션을 코딩하는 것은 항상 어렵습니다. GC의 사용으로 인해 가져다주는 생산성이 더 흥미로울 수도 있습니다.
표현력
저는 Clojure와 같은 동적으로 타입이 지정된 언어가 강력한 타입이 지정된 언어와 비교했을 때 다음과 같은 기능을 허용한다고 생각합니다:
- 빠르게 프로토타입을 만들고 결과물에 빨리 도달하기 위해서 필요합니다.
- 짧은 프로그램을 작성하는 것이 중요합니다. 동일한 이해 수준에서 프로그램 크기를 강제로 줄이지 않고, 1000줄의 코드를 가진 프로그램을 유지하는 것이 10000줄의 코드를 가진 프로그램을 유지하는 것보다 선호됩니다. 예를 들어, Java와 Clojure로 작성한 동일한 프로그램 사이에는 최소 5에서 10배 이상의 차이가 있습니다. 이는 매우 크며 프로그램 유지보수에 영향을 줍니다.
- 핵심 요소에 집중하기.
마지막으로 이 포인트도 중요합니다. 강력한 유형의 언어에는 유형 시스템에 항상 새로운 기능이 출시된다는 문제가 있습니다. 타입에 대한 3개의 박사 학위를 가진 소수의 사람들은 이해하기 어려운 기능을 항상 사용하고자 할 것이며, 각 새로운 기능은 언어에 복잡성의 층을 추가합니다.
이러한 언어들은 타입 폭발에도 영향을 받습니다. 데이터의 작은 변형마다 해당 유형이 있어야 하며(Enum, Option 등이 도움을 줄 수 있더라도), 이는 코드베이스를 무겁게 만들고 유형 사이의 변환 함수를 추가합니다. 유형을 조작하고 확장하는 것은 꽤 복잡한 작업입니다.
성능
쓰레기 수집기가 성능에 미치는 영향에 대해 이야기했어요. 하지만 쓰레기 수집기가 있는 언어들 사이에도 성능에 엄청난 차이가 있습니다.
인터프리터 언어(Python 기본 버전과 같이)는 일반적으로 컴파일된 언어보다 훨씬 느립니다. JVM과 같은 플랫폼은 매우 뛰어난 성능으로 유명합니다 (대부분의 빅데이터 도구가 JVM에서 실행된다는 것은 우연이 아닙니다).
그렇지만 여기서도 우리는 스스로에게 물어봐야 합니다: 언어 성능이 정말 중요한가요?
대부분의 애플리케이션은 궁극적으로 부하가 적고 초당 요청 횟수도 적을 것입니다. 대부분의 시간은 I/O에서 소요되며, 따라서 언어 성능은 무시할만큼 작을 것입니다.
일반적인 웹 애플리케이션 프로젝트는 초당 몇 개의 요청을받는 것에 언어 선택이 영향을 미치지 않습니다. 물론 많은 애플리케이션 인스턴스를 가진 대형 웹 사이트에서는 영향을 미칠 수 있으며, 더 효율적인 언어로 서버의 이득(따라서 돈)을 얻는 것이 정당화될 수 있습니다. 또한, 현재 사용 중인 언어에 팀이 편안하다면 그것이 가장 중요한 부분일 수 있습니다. 균형을 유지하는 것은 여러분에게 달려 있습니다.
원시 성능은 한 가지이지만, 동시 및 병렬 프로그래밍을 쉽게 할 수 있는 능력은 다른 문제입니다. 사용하는 플랫폼 및 언어에 따라 더덜 복잡할 수도 있으므로 시작하기 전에 해당 문제를 연구해야 합니다. 일부 플랫폼(Erlang/OTP 등)은 이러한 문제에 우아하게 대답할 수 있습니다.
함수형 프로그래밍, 객체
언어는 종종 객체 언어, 함수형 언어 등과 같은 패밀리로 나뉘기도 합니다. 다른 것들도 있습니다. 일부 언어는 여러 범주에 적합하거나 다른 방식으로 기능을 추가할 수 있어서 이러한 범주를 정의하기 쉽지 않습니다. 따라서 해당 주제에 대해 자세히 다루지 않겠습니다.
하지만, 함수형 프로그래밍은 매우 흥미로운 분야입니다. 프로그램을 변경할 수 없는 데이터로 설명하고 함수를 적용함으로써 버그를 크게 제한할 수 있습니다. 그런데, 함수형 프로그래밍은 정적 타입과는 다르다는 사실이죠!
생태계
생태계는 매우 중요합니다. 종이 위에서 매력적으로 보이는 언어들이 있지만, 결국에는 심각하게 사용하기에는 너무 작은 생태계를 가지고 있습니다.
mTLS 및 HTTP 2를 실행할 수 없고, Kafka 및 Rabbit MQ와 같은 클라우드 도구와 상호 작용할 수 없는 이유로 생태계가 부족하다면, 문제가 발생할 수 있습니다.
이러한 플랫폼의 장점은 JVM, Python 또는 Golang과 같은 것입니다. 여기에는 많은 수의 우수한 라이브러리가 있어서 필요한 경우에도 라이브러리 부족으로 막히지 않을 것입니다.
또한 패키징 및 의존성 관리도 중요합니다. Rust의 cargo, mavenJava 또는 leinClojure과 같은 도구를 사용하여 의존성을 적절히 관리하고 빌드해야 합니다. 외부 도구(예: 린터)도 큰 장점입니다(Golang의 경우 특히 강합니다).
요약하자면, 생태계는 간과해서는 안 되는 요소입니다.
개인적인 선호도
마침내 우리 모두는 뇌가 서로 다르게 연결되어 있기 때문에 주관적인 기준에 따라 특정 언어의 매력에 빠질 것입니다.
내 경우, 예를 들어, 나는 더 이상 "엔터프라이즈" 자바에서 일할 일이 없기를 바랍니다. 주의하세요. 나는 Java 언어를 널리 사용 가능하고 매우 흥미로운 언어로 여기지만, 오늘날 Java로 개발하는 방식이 사용되는 프레임워크 수준에서는 일탈에 가깝다고 생각합니다. 나는 해당 주제에 대한 몇 가지 기사도 여기저기에 가지고 있습니다. 그리고 일반적으로 알고 있는 언어를 사용하는 것이 가장 흥미로운 것으로 남아 있습니다.
결론
이해해야 할 중요한 점은 언어 선택이 먼저 프로젝트의 유형과 관련이 있다는 것입니다. 이전에 설명한 대로 GC를 용납할 수 없는 경우 선택이 제한됩니다. 특정 생태계 (예: Kubernetes)에 통합하고 싶다면 선택지도 제한됩니다.
그러나 종종 필요에 맞는 여러 언어가 있을 수 있습니다. 이 경우 당신이 결정할 차례입니다. 결국 '고전' 선택지에 정말 나쁜 언어는 없지만, 더 나쁜 사용법이 있을 뿐이라고 생각해요.
간단한 영어로 🚀
In Plain English 커뮤니티의 일원이 되어 주셔서 감사합니다! 떠나시기 전에:
- 반드시 만세를 하고 작가를 팔로우해 주세요 ️👏️️
- 팔로우하기: X | LinkedIn | YouTube | Discord | 뉴스레터
- 다른 플랫폼 방문하기: CoFeed | Differ
- PlainEnglish.io에서 더 많은 콘텐츠를 만나보세요