brunch

You can make anything
by writing

C.S.Lewis

by Razelo Feb 18. 2022

[무작정 언어탐방기] Rust Language 후기

무작정 공부해본 Rust 언어의 첫인상 

며칠전 프로젝트가 마무리되면서 잠시 여유를 가질 수 있었고 덕분에 예전부터 눈독들이고 있던 Rust 언어를 배워보고 싶다는 생각에 무작정 공식 Rust 공식문서를 읽었다. 


친절하게 설명된 문서라는 생각이 들었고 읽는데 한글로 번역된 문서도 존재해서 개념을 파악하는데 많은 시간이 걸리지 않았다. 


현재는 IO프로젝트까지 읽고 해당 파트의 grep프로젝트 코드까지 작성한 상태이다.

 

그래서 오늘은 며칠간 빠르게 살펴본 Rust 언어의 첫인상에 대해 간략하게 이야기하는 시간을 가져보도록 하겠다. 



역시나 모든 언어에 존재하는 변수와 데이터 타입, 함수, 제어문에 대해 배웠는데 한가지 흥미로운 점은 다른 언어에서는 볼 수 없었던 개념이 언어 전반에 녹아있다는 점이었다. 


예전부터 러스트를 관심갖고 지켜보면서 러스트로 만든 프로젝트 사이트를 구경하면서 시간날때 배워봐야겠다는 생각을 하면서 어떻게 하면 속도와 메모리 안전성을 둘 다 가져갈 수 있는지 궁금했었다. 그리고 공식 문서에서는 그와 관련된 내용으로 소유권과 참조자 그리고 빌림체크에 대해 소개하고 있었다. 


그 중 가장 신기했던 점은 바로 빌림을 검사한다는 내용이다. 또한 빌림 검사에 더해 스코프에서의 유효성까지 추가적으로 검사하기에 dangling pointer 문제도 해결할 수 있다는 점이 신기했다. 그래서 이러한 점들 덕분에 Managed 언어에서 고질적으로 발생하는 문제들이 발생하지 않고 물론 참조되지 않는 메모리가 혼자 덩그러니 남아있을 이유도 없어지게 된다. 


그러나 위와 같은 장점이 있더라도 결국에는 역설적으로 이러한 장점들이 개발 속도를 늦출 것이라는 생각이 들었다. 


아직 고급 기능인 클로저나 스레드 혹은 스마트 포인터에 대해 깊게 공부하지 않았지만 작은 Cli 프로젝트를 만들어본 현재 상태에서는 그렇게 느꼈다. 왜냐하면 Ownership과 빌림 검사라는 개념이 있다는 내용을 보면서 공부하기 이전에는 이것이 어떤 기능으로써 즉 하나의 형태로써 존재하는 것이지 않을까 추측했기 때문이다. 그러나 해당 개념은 마치 일종의 언어 철학처럼 코드 작성시 반드시 고려해야할 고려사항이었다. 


말 그대로 언어의 설계에 녹아있어서 이런 철학을 모른다면 이후로 단 한줄의 구문도 작성하지 못할 것이라는 생각이 들었다. 


Rust 언어가 러닝커브가 높다는 말을 들었는데 그 이유도 이러한 함축적인 개념들을 잘 이해하고 앞으로 작성하게될 코드에서 지속적으로 이러한 개념들을 고려해야하는 것이 어렵기에 그런 말을 하는 것이라고 생각했다. 또한 다른 언어에서는 없었던 개념이기에 생소함에서 오는 어려움이 러닝커브를 높이는 것이라고 생각했다. 


짧은 기간동안 배우게 되어서 아직 모르는 개념이 많다. 솔직히 말해서 아직도 Rust에서 말하는 String과 String 리터럴의 차이에서 등장하는 슬라이스라는 개념은 명확히 이해가 되지 않는다. 또한 Rust 컴파일러가 특정 변수의 생명주기인 라이프타임을 추적하면서 어디까지 살아있는지 체크하기 위해 사용하는 기능 중의 하나인 'a 혹은 'static 이라는 개념이 있는데 이것도 감이 잡히지 않는다. 


한번밖에 읽어보지 않아서 맥락을 파악하기가 어렵다. 


앞으로 이 부분만 중점적으로 읽어봐야겠다는 생각이 들었다. 그리고 다른 언어들과는 다르게 String에 대해서 아주 다양한 옵션을 제공하며 깊게 다루는 언어라는 생각이 들었다. 



흥미로운 점은 함수에서 Null을 반환할 수 없게 Result<T, E>를 반환하도록 한다는 점이다. 


즉 Null이 없다. 


아예 처음부터 Result<T, E>를 반환하게 만들었다. 대신 제너릭 표기에서 E가 존재하는 것을 보면 알 수 있있듯이 Caller에게 에러를 전파시키면서 에러 처리를 위임시키는데 이 때문에 Caller가 마음대로 예외를 처리할 수 있게 해준다. 물론 제대로된 결과가 나왔다면 Caller에게 Ok()를 던지는데 이때 원하는 방식으로 이후 프로세스를 진행하면 된다.


도저히 처리할 수 없는 순간에는 ctrl + c와 같은 개념이 존재한다. 바로  panic!이라는 개념이다. 다른 프로그래밍 언어를 사용해본적 있는 사람이라면 짐작할 수 있는데 말 그대로 Panic이다. 그냥 멈추는 동작이다. 터미널에서 ctrl + c를 눌렀을때 처럼 동작이 멈추고 실행되고 있던 프로세스 밖으로 나가 버린다. 


한가지 더 재밌는 점은 열거형의 다양성이다. 


열거형을 굉장히 다양하게 사용할 수 있다. 즉 열거형의 응용이 엄청나다. 구조체와 붙여서 자주 사용하는데 제너릭으로 만들어서 사용할 수도 있고 나중에 검사할 적에는 match 구문을 통해 분기로 갈라지면서 검사하는 기능을 가지고 있다. 이때의 각 분기를 Arm이라고 한다. 


match는 특정 리턴 값이나 전달받은 값에 대해서 그 값이 어떤 타입인지 혹은 값을 검사하여 Arm으로 분기시켜 처리한다. 이걸 보면서 switch와 비슷하다고 생각했다. 



예전에 어느 커뮤니티에서 러스트를 비판하는 글을 읽은 적이 있다. 


해당 글에서 러스트의 개발 속도와 스타일을 문제삼았다. 개발속도가 느리다는 점은 이미 위에서 언급했기에 타당한 비판이라고 생각하지만 스타일을 언급하는 의견에서는 이해되지 않은 점은 바로 러스트가 구조체를 통해 예전 C언어 스타일에서 객체지향을 흉내내려고 애쓴 방식과 아주 유사하게 OOP를 처리한다는 의견이었다.


당시 해당 의견을 읽으먼셔 왜 러스트는 멀티패러다임 언어인데 이런 비판을 받을까? 객체지향도 지원하는데 왜 이런 비판이 있는걸까?라는 고민을 했다. 


고민의 이유는 간단했다. 당시까지 내가 기존에 알던 Class 문법이 러스트에도 당연히 존재할 것이라고 착각했기 때문이다. 


당시 나의 생각이 안일했던 것은 객체지향이라면 무조건 Class 관련 문법이 존재해야 한다고 생각했던 점이다. 객체지향을 문법 그 자체라고 생각한 사고방식의 잘못일 수 있다. 대상을 객체지향적으로 바라보는 것에 문제 해결의 실마리를 찾는다면 문법은 아무래도 상관없을 수 있을 수도 있다. 그런데 실제로 실세계를 객체지향적으로 바라보다보니 지금과 같은 문법이 가장 적합했기 때문에 우리에게 익숙한 Class 관련 문법이 계속 사용되는 것은 아닐까라는 생각도 들었다. 


하지만 이번에 공부하면서 왜 커뮤니티에서 해당 비판을 했었는지 알 수 있게 되었다. Class 문법조차 없었고 구조체를 필드로 가져가면서 구조체 메서드를 impl을 통해 정의할 수 있게 만들어주고 대상의 행위를 정의해주는 방식으로 구현되는 방식이었다. 


Class에는 당연히 속성이 있을 것이고 행위가 있을 것이기에 우리가 흔히 접하는 Python3이나 Java에서는 당연히 필드를 작성해주고 메서드도 작성해주면 그만이다. 그런데 사람들이 말하기를 예전에 C 언어에서 객체지향 개념을 사용할 적에 구조체를 필드처럼 사용해서 속성을 정의했고 함수 포인터를 사용해서 행위를 정의하는 방식으로 사용했고 이것이 문제가 많았기에 꼼수같은 테크닉을 많이 사용했다고 한다. 즉 코드 상에 테크닉으로 구현한 것이다. 그래서 Rust에서도 위에서 언급한 방식처럼 쓰는 것이 아니냐는 비판이 있는 것이다.


물론 C언어와 정확히 동일하게 작성하는 것은 아니겠지만 Class 처럼 사람들이 떠올렸던 익숙했던 개념이 아니었다는 점에서 사람들의 기대에 부응하지 못했기 때문에 해당 의견이 나왔다는 생각이 들었다.  


Rust를 공부하면서 모두에게 익숙한 기존의 Class 문법이 있었으면 좋겠다는 생각을 했다. 하지만 이것도 결국 Rust의 생소함 때문이라는 생각을 했다. 아직 언어 철학에 대해 깊게 알지 못하지만 반드시 이런 방식을 택한 이유에는 Safety를 위해서 라는 생각이 들었다.  



위에서 언급한 측면에서 보더라도 마찬가지인 점은 바로 빌림 검사기나 소유권의 개념 그리도 변수의 생명주기를 추적해서 더 작은 스코프의 변수가 다른 곳에서 참조됨에도 불구하고 미리 소유권이 말소된다면 엄격하게 컴파일조차 되지 않는 모습을 보면 이 언어가 각광받는 핵심적인 이유는 Speed가 아니라 Safety측면에서 월등하게 뛰어나기 때문이라는 생각이 들었다. 


물론 C/C++과 대등하거나 혹은 근접한 속도로 실행된다고 한다. 하지만 그럼에도 불구하고 러스트를 배우면서 느낀 점은 러스트 컴파일러 설계자들이 러스트 언어를 설계하면서 "너희들이 정말 실수하지 않게 만들어줄게. 실수하고 싶어도 못하게 만들어줄게."라는 각오를 하고 만들었다는 느낌을 받았다. 


결국 개발속도가 느려질 수 밖에 없는 언어라는 점은 분명하다. 


러스트를 홍보하는데 많은 키워드가 있다. 열성 Rust 사용자들인 Rustean도 열띤 홍보를 하고 있다. 그럼에도 불구하고 아직은 회의적인 시각이 있다. Discord가 Go로 만들었으면서 이후에 Rust로 갈아엎는 이유는 단지 Rust가 Go보다 더 뛰어나서가 아니라 사업적 측면에서의 선택을 고려하지 않을 수 없었기 때문이라고 생각했다. 


당연히 스타트업 입장에서는 빠른 개발과 빠른 출시가 우선이다. 그런 면에서 Go를 선택했을 것이고 회사가 안정궤도에 올랐으니 돈과 시간이 생겼을 것이기에 가능한 옵션 중에서 채택하여 Rust로 갈아엎는 일을 벌이고 있는 것이라는 생각이 들었다. 


결국 언어의 우위가 아니라 프로젝트를 진행하면서 오고갔던 제안들과 고민 속에서 선택된 옵션 중 하나라는 생각을 했다. 



일부 의견 중에는 Web3.0을 언급하면서 Solana를 이야기하는데 그것을 Rust가 메이저 언어로 채택될 수 밖에 없는 이유라고 말한다. 언어가 혁신의 중심이 되는 것은 아니라는 생각을 해서 동의할 수 없었다. 


도구가 훌륭했기 때문에 작품이 훌륭하다는 말과 다름없다고 생각해서 동의할 수 없었다. 하지만 그럼에도 불구하고 속도와 안전성 때문에 Rust를 택하겠다면 타당하게 선택이 된다고 생각한다. 그렇기 때문에 개발 속도와 비용, 러닝커브와 같은 모든 것을 고려하여 선정할때 매력적인 옵션이 될 수 있다고 생각했다. 


다만 모든 프로젝트에 필수적이지는 않다고 생각한다.  



Rust는 특히 WASM과 관련하여 언급하고 있는 내용들이 많았다. 이 부분은 전부터 많이 궁금했던 내용이었다. 그래서 Rust를 공부해본 김에 WASM까지 공부해보고 싶다는 생각이 들었다. 그 이유는 WASM으로 어떤걸 만들어낼 수 있을지에 대해 기대하고 있었기 때문이다.


지난번에 팔로우를 한 팔로워 님께서 흥미로운 글을 올리셨다. 


자신의 게임 엔진을 WASM으로 포팅하여 웹에서 돌아가게 만든 후기를 올리셨다. 


그분 말씀대로 현재는 WASM 개발환경이 성숙하지 못하고 불편한게 많다고 한다. 하지만 그럼에도 불구하고 앞으로 WASM을 통해서 웹에서 돌릴 수 있는 무언가 재미난게 쏟아질 거라는 생각이 들면서 상당히 구미가 당겼다. 


흥미로운 기술이 나왔는데 고작 개발환경이 불편하다고 해서 가만히 있을 사람들이 아니기에 어떻게 해서든 관련 툴이든 기술이든 뭐가 되었든 더 나올거라고 생각한다. 그렇기 때문에 앞으로 이번주처럼 여유를 가질 수 있는 시간이 생긴다면 WASM도 공부해보고 싶다는 생각이 들었다.

 


짧은 시간이기도 했고 모든 개념을 다 알아본 것은 아니지만 정말 재밌게 공부한 언어가 되었다. 


생소한 개념이 등장했는데 이후에 써볼 기회가 없더라도 이런 개념들이 있다는 걸 알고 있는 것도 많은 도움이 될 거라고 생각했다. 


도움이 되는 것과 별개로 개인적인 흥미를 느꼈기 때문에 만족했으며 언젠가 현업에서 써볼 기회가 왔으면 좋겠다고 생각했다. 



짧은 시간에 공부한 내용이기에 부족한 부분이 있다면 댓글로 알려주시기 바랍니다. 


읽어주셔서 감사합니다. 


Rust 공식문서: https://www.rust-lang.org/learn



브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari