소프트웨어 잘하는 방법, 인터페이스
어떤 이야기를 할까 고민 끝에, 거창하고 부담스러운 주제 '소프트웨어 잘하는 방법'을 화면에 적자마자 떠오른 두 가지가 SoC와 인터페이스다. 여러 주제가 있고, 열띤 토론을 펼칠만한 이야기도 많지만 나의 바이오 심층 신경망이 활성화되어 선정된 두 가지 강력한 주제다. 좋은 소프트웨어가 무엇인지에 대해서는 따로 이야기해야 할 만큼 큰 주제가 될 수 있겠지만, 나의 경험에서 모든 좋은 소프트웨어는 잘 갖춰진 인터페이스를 통해 관심사가 적절히 분리된 소프트웨어였다.
SoC에 대해서는 지난번에 소개를 해봤고 오늘은 인터페이스에 대해서 이야기해보려 하는데, 사실 이 둘은 하나의 세트나 다름없다. 물론 각각이 따로 의미가 있지만, 둘을 함께 잘할 때 진정한 효과를 볼 수 있다. 그 이유와 사례들에 대해서 최대한 재미있고 쉽게 이야기해 볼 것을 도전해 본다. 시작!
https://brunch.co.kr/@msaltnet/23
영화 그래비티에서는 우주선과 국제우주정거장(ISS, International Space Station)이 연결되어 있는 장면이 나온다. 도킹은 우주공간에서 두 우주선이 물리적으로 연결되는 것을 뜻하는데, 당연히도 두 우주선은 다른 공간, 다른 시간에 제작되고 언제 어떻게 도킹될 것인지 정하고 제작되지 않음에도 불구하고 찰떡 같이 딱 맞아 붙어야 임무를 완수할 수 있다. 땅에서 만들어 가지고 올라가서 우주에서 연결이 되어야 한다.
두 우주선이 연결되는 접점은 사전에 정해진 규격과 방식으로 만들어지고 동작하기에 어디에서 누가 만들어도 국제적으로 문제가 없는 것인데 이것이 오늘 이야기할 '인터페이스'라고 볼 수 있다.
인터페이스(interface)는 서로 다른 두 개의 시스템, 장치 사이에서 정보나 신호를 주고받는 경우의 접점이나 경계면이다. 즉, 사용자가 기기를 쉽게 동작시키는데 도움을 주는 시스템을 의미한다. - 위키백과
인터페이스란 말 그대로 마주 보고 있는 면이란 뜻으로, 시스템 간 상호 작용을 가능하게 하는 접점이며, 소프트웨어 개발에서도 필수적인 개념이다. 소프트웨어 모듈이나 컴포넌트가 다른 모듈이나 컴포넌트 또는 사용자와 만나는 접점이 바로 인터페이스가 된다. 사용자와의 접점이라는 점에서 애플리케이션의 화면과 그 속의 버튼이나 아이콘 등이 모두 인터페이스라고 볼 수 있으며, 사용자 인터페이스(UI, User Interface)라고 한다.
사용자 인터페이스라는 기술적인 용어가 일반인들에게도 익숙하게 된 것은 아이폰 때문이 아닐까 싶다. 아이폰 돌풍이 시작되었을 때, 사람들에게 아이폰이 왜 좋냐 물어보면, 구체적인 이유를 나열하기보다 그냥 사용하기 편하다는 대답이 많았다. 물론 지금은 스마트폰의 사용자 인터페이스가 대동소이해졌기 때문에 카메라나 보안을 이유로 언급하는 사람이 많지만, 그럼에도 불구하고 아이폰 쓰던 사람이 계속 아이폰을 사용하는 이유는 특유의 사용자 인터페이스에 익숙해졌기 때문이다. 그만큼 아이폰의 사용자 인터페이스는 독자적이고 스티브잡스가 살아있을 때 가장 신경을 많이 썼던 부분 중 하나다.
사실 멀리 우주까지 가지 않아도 비슷한 사례는 많이 있다. 매일 사용하는 스마트폰의 충전단자, 컴퓨터의 USB 포트 같은 것들이 인터페이스의 좋은 예가 될 수 있다. 그럼에도 불구하고 굳이 우주선의 도킹까지 들먹인 데에는 특별한 이유가 있는데, 인터페이스라는 약속이 갖는 무게에 대해서 강조하고 싶었기 때문이다.
개발자가 만드는 모듈은 다른 개발자가 만드는 모듈과 서로 상호작용하면서 동작하게 된다. 물론 앱이나 시스템을 한 명 또는 일부 개발자가 모두 만들 수도 있지만 관심사의 분리가 잘 되어 있으면 협업과 테스트가 쉽고, 유지 보수 비용을 낮춰서 효율적으로 개발할 수 있다. 이렇게 분리된 모듈이 서로 상호작용할 때 사용하는 것이 바로 인터페이스다.
관심사의 분리를 소개할 때 얼마나 더 작게 나눌 것인지에 대해서 잠깐 언급을 했었다. 오징어 게임은 기존의 군대와 같은 조직을 보다 더 작게 병사 하나 하나로 분리해 놨고, 그것이 추가 비용을 발생시키지만 통제와 확장에는 유리하다는 점 때문에 소프트웨어에서는 적극적으로 모듈을 잘게 나눌 필요가 있다고 했다. 그 비용이 추가되는 부분 중에 인터페이스를 생성하는 부분이 포함되어 있다.
컴퓨터 USB 포트를 생각해 보자. 만약 두 개의 장치를 한 사람이 만들다고 한다면 굳이 USB 포트라는 연결 방식을 인터페이스라는 약속으로 정의하고 그 동작에 대해서 자세하게 서술할 필요가 없다. 그냥 임의로 정하거나 적당히 양쪽의 연결 부위를 손보면 끝이다. 훨씬 간단하고 빠르다. USB의 규격이 얼마나 복잡하고 많은 사람들이 모여서 결정하게 된 것인지 알게 된다면 그 수고가 꼭 필요한 것인지 되묻고 싶어지는 것이 일반적인 반응일 것이다.
걱정하지 않아도 될 것은, 개발팀에서 만드는 분리된 모듈 간의 인터페이스가 USB 포트처럼 국제적인 규격으로 만들어지는 것이 아니기에 그렇게 많은 비용이 추가되는 것이 아니라는 점이다. 그럼에도 불구하고 개발자는 대충 적당히 연결부위를 만들 생각을 하면 안 된다. 비록 같은 팀의 동료가 사용할 인터페이스라도 인터페이스는 약속이고, 약속을 지키지 않는 것은 서로에게 비용과 신뢰의 문제를 야기하기 때문이다.
내 모듈의 인터페이스가 정해지면 내 모듈을 사용하는 동료는 그 인터페이스에 대한 정보만을 가지고 자신의 모듈을 만들 수 있다. 내 모듈이 어떻게 구현되는지, 어떻게 동작하는지 관심을 끄고 본인의 업무에 집중할 수 있다. 이것이 바로 인터페이스의 힘이고, SoC(관심사의 분리)의 진정한 실현이다. 인터페이스가 있기에 다른 부분에 대해서는 철저하게 관심을 끌 수 있는 것이다.
종종 인터페이스가 잘 못되면 수정하는데 비용이 발생한다. USB 포트와 같은 인터페이스의 설계나 구현이 잘 못되어도 그렇고, 인터넷의 서버 간의 통신에서도, 우주선의 도킹을 위한 인터페이스도 마찬가지다. 각각 비용의 크기는 다르지만, 때때로 그 약속 하나 때문에 전체 시스템이 영향을 받을 수 있기에 인터페이스를 잘 정의하고, 잘 지키는 것은 정말 중요하다. 힘들게 우주까지 올라갔는데, 인터페이스에 문제가 있어서 도킹을 못한다고 생각해 봐라. 상상만으로도 끔찍하다.
어떤 모듈의 인터페이스가 정해진 다는 것은 그 모듈의 동작과 사용 방식이 정해지는 것을 의미한다. 따라서, 모듈이 구현되기 전에도 그 모듈과 관련된 부분을 인터페이스에 맞춰서 구현할 수가 있다. 마치 USB라는 인터페이스에 맞게 개발하면 해당 인터페이스를 지원하는 어느 기기와도 연결이 될 수 있는 것처럼 말이다. 하지만 모든 개발자가 그것을 잘하는 것은 아니고, 초급 개발자들은 인터페이스만으로 개발하는 것에 어려움을 느끼기도 한다. 보통 직접 사용을 해보면서 개발을 하는 것을 선호한다. 반면, 고급 개발자는 인터페이스에 맞춰서 자신의 모듈을 개발하는데 망설임이 없고, 심지어 인터페이스가 불분명한 경우에도 적절히 개발을 하면서 해당 모듈 담당자에게 인터페이스에 대한 피드백을 준다.
보통 두 모듈이 동시에 개발될 때 인터페이스를 정하고 동시에 개발이 진행되지만, 중간중간 만나서 조금씩 수정하곤 한다. 뛰어난 개발자는 인터페이스도 잘 만드는데, 필요한 부분과 전체 상황에 대해서 명확하게 이해하는 메타인지가 뛰어나다. 그래서 처음부터 설계를 잘하고, 동시에 설계가 크게 바뀌지 않는 선에서 구현도 잘한다. 뿐만 아니라 본인이 만드는 모듈의 기능을 확실히 이해하고, 사용자의 요구 사항도 자세히 파악해서 인터페이스를 만들다 보니, 종종 혼자 만드는 모듈들도 인터페이스를 만들어 분리하면서 개발한다. 함께 동작하는 두 개의 모둘을 만들면서 서로 주고받는 데이터나 함수를 호출하는 방식 등을 따로 정하지 않고 개발할 수도 있지만, 분리가 필요하다고 생각하는 모듈이라면 굳이 인터페이스를 만들어서 개발하는 것이다.
이렇게 인터페이스를 만들고 개발을 하면, 해당 모듈을 다른 과제나 제품에서 다시 사용하기 좋다. 즉, 재사용성을 고려하면서 개발하게 되는 것이다. 추가비용이 들지만 장기적으로 이득인 것이다. 사실 관심사의 분리 SoC를 잘 지키는 것도 당장 추가 비용이 들지만 장기적으로 이득이 된다는 점이 중요하다. 프로젝트를 하다 보면 이처럼 길게 보고 일을 해야 할 때가 많은데, 당장 편하자고 간단한 방식으로 적당히 구현해 놓았다가 나중에 몇 배의 추가 비용이 들어가는 일이 생기기도 한다. 결국 거기서 고수와 하수가 구분되는데, 고수는 조금 힘들고 어려운 길이라도 필요하다고 판단되면 적합한 해법을 찾아서 적용하는 반면, 고수의 판단을 이해를 못 하고, 당장 일이 많아지는 것을 귀찮아하며 투덜거리는 것이 대표적인 하수의 모습이다.
날이 갈수록 인터페이스가 중요해지는 것은 시스템이 점점 더 크고 복잡해지기 때문이다. 그것은 모듈의 기능도 중요하지만 사용성도 중요해졌다는 것을 의미하기도 한다. 요즘에는 기능이 잘 동작하는 라이브러리라도 사용성이 좋지 않으면 사용자로부터 외면받고 만다. 돌이켜보면 초기 아이폰은 갤럭시보다 기능이 훨씬 더 적었다. 하지만 있으면 좋은 것은 없애버리는 아이폰의 전략은 사용성 측면에서 확실한 성공 요소가 되어서 수많은 사용자를 끌어들였다. 요즘 핫한 AI 기술도 비슷하다. AI 모델을 배포하고 받아서 사용하고, 서비스를 만들 수 있는 수많은 제품과 프레임워크가 나오고 있는데, 이때 사용성은 빼놓을 수 없는 경쟁력 지표가 되었다.
작성하고 있는 글 모음은 후배 개발자들에게 하고 싶은 말들이기도 한데, 개발자로 성공하고 싶다면 본인이 만드는 프로그램, 또는 짧은 코드조차 그것을 사용하는 사용자, 어쩌면 동료나 상사에게 사랑받을 수 있는 제품을 만들듯이, 코드와 프로그램을 만들라는 말을 전해주고 싶다. 분명한 역할로 잘 나눠져 있고, 편리한 인터페이스를 제공하는 코드, 모듈, 프로그램을 만들 수 있다면 어느 도메인, 어느 조직에서라도 성공할 수 있는 소프트웨어 엔지니어가 될 수 있다는 것을 기억했으면 한다.