웹 개발자도 수학을 배워야 할까

Created
6/5/2021, 1:54:00 PM
Tags
CS
ETC
Subtitle
4달여간의 수학 공부 리뷰
해당 글은 개인적인 주관이 담긴 글입니다.

웹 개발자에게 수학은 필요한가?

4달간 2진수, 집합, 행렬, 벡터, 확률, 통계등을 공부를 했다.
'도움이 되었나' 라고 묻는다면 그런 편인거 같다.
그렇다면 웹 개발자에게 수학 공부는 필수적인가?
개인적으로는 그렇지 않다고 생각한다. 운영체제, 네트워크, 언어, 기타 기술 공부 등이 더 우선시 되어야 한다고 생각한다.
그 이유는 위의 것들과 달리 대부분의 수학 공부가 한다고 해서 당장에 할 수 없는 것들을 할 수 있게 되진 않기 때문이다.
10진수를 2진수로 변환할 수 있게 된 것이 우리의 업무시간을 단축시켜 주지 않는다.
다만, 특별한 개발자로 성장하기 위해서는 수학공부는 필요하다고 생각한다.
특별한 개발자라는 말이 굉장히 모호한데, 다방면의 재능이라 하나의 단어나 분야로만 설명하기 어렵다.
때문에 아래 글에서 그것이 무엇인지 같이 살펴보도록 하자.

나는 생각한다 고로 존재한다.

René Descartes (르네 데카르트)
French philosopher
Born: March 31, 1596, Descartes, France
Died: February 11, 1650, Stockholm, Sweden
아주 유명한 문구라 한 번쯤은 다들 들어봤을 것이다. 혹은 오늘 처음 본 것이라도 좋다.
이 문구를 보기 전과 후에 우리의 인생은 과연 달라졌을까?
대부분 아닐 것이라 생각한다. 그런데도 허울 뿐인것 처럼 보이는 이 문장은 왜 유명할까.
우리가 배워야 할 것은 "나는 생각한다 고로 존재한다." 라는 문장의 결론이 아니다.
데카르트가 철학의 기본이 되는 의심할 수 없는 절대 참인 명제를 찾기 위해 고민했던 과정을 배우려고 했을 때, 이 문장은 비로소 의미가 있다.
프로그래머에게 있어서 수학 역시 이와 같은 맥락에서 이해할 수 있다. 2진수를 10진수로 계산 할 수 있다고 해서 갑자기 더 좋은 코드를 작성 할 수 있게 되지 않는다.
의미있는 수학공부란 선배 개발자들이 2진수를 통해서 어떤 문제를 해결하려고 했는지 이해하고, 2진수를 가지고 스스로 그 문제에 도전함으로써 프로그래밍 사고를 훈련하는 것이라고 생각한다.

학습과 훈련

개발자가 수학을 공부한다는 것은 과연 어떤것일까에 대한 고민을 오랜기간 했었는데, 그 중 훈련이라는 단어가 내겐 참 와닿는 단어였다.
내가 생각하기에 개발자가 성장하기 위해서는 학습과 훈련이 필요하다고 생각한다. 이 둘은 다르다. 학습은 새로운 것을 보고 배우는 것이다. 새로운 언어의 기술스펙, 프레임워크, 운영체제등의 내가 모르는 것을 익히는 것이다.
학습의 결과는 대체로 눈에 띈다. 어제까지 내가 하지 못한 것을 하게 되고, 새로운 것을 만들 수 있게 된다. 그렇기 때문에 더 나은 개발자로 성장하기 위해서는 모두 학습하려 한다.
그에 비해 훈련은 내가 모르는 것을 알아가는 과정과는 거리가 멀다. 배운것을 의식적으로 반복하여 무의식적으로 좋은 방법을 선택할 수 있게 하는 과정이다. 예를 들면 TDD, 애자일, 디자인 패턴등은 학습만으로는 변화하지 않는다. 꾸준한 의식적인 연습을 필요로 한다.
즉, 수학을 공부한다는 것은 의식적으로 프로그래밍적인 사고를 통해 코드를 작성하게 연습하는 것이다 .

연역적 사고와 귀납적 사고

프로그래밍적 사고란 무엇인가? 답을 위해 다음 문제를 살펴보자
문자열인 일의 자리 두 수를 더해 그 결과를 출력하는 기능을 구현하라. ( 타입 변환은 할 수 없다. )
이 문제를 어떻게 풀 수 있을까? 가령 이렇게 풀 수 있을 것이다.
function calculate(a, b){ if(a == "1"){ if(b == "9") { return "10" } if(b == "8") { return "9" } ... } if(a == "9"){ if(b == "9"){ return "18" } } }
JavaScript
더 깔끔해질 수는 있겠지만, 덧셈이라는 규칙을 사용할 수 없다면 조건을 다 따질 수 밖에 없다. 이건 아니라고 생각하는가? 나 역시 동의한다. 하지만 나는 꽤 많은 부분에서 이렇게 코드를 작성하고 있었고, 유명 오픈소스 혹은 팀 내의 코드 리뷰를 하면서도 이러한 코드를 많이 보아왔다. 문제가 발생할때마다, 예외를 추가함으로써 문제를 해결하는 방식 말이다.
제대로 돌아가길 기도하며 조건을 하나씩 바꿔본다.
특히, 키보드 앞에 있을 때는 쉽사리 이러한 액션을 피해가기 어렵다. 될 때까지 키보드와 마우스를 움직이며 하나씩 해보는것은 우리가 처음 코딩을 배울 때부터 하던 것이 아닌가? 우리는 실패의 경험을 쌓아가며 성공에 도달하는 귀납적 프로그래밍에 익숙해져 있기 때문이라 생각한다.
하지만 필요에 따라 우리는 다른 방법으로 문제를 해결할 수 있어야 한다. 키보드에서 떨어져 모든 조건을 만족하는 가설(공식)을 세우고 그것을 코드로 작성하는 연역적 프로그래밍이 필요하다.
const mappingTable = { "0": "00000", "1", "00001", ... "18", "10010"], }; function calculate(a, b){ const binary = addBinary(mappingTable[a], mappingTable[b], 0 , "0"); return getKeyByValue(mappingTable); } function addBinary(a, b, result, i, carry) { //i와 carry는 각각 자릿수와 올림여부 if(a[4-i], b[4-i], carry are all "1") { carry = "1" result = "1" } ... if(a[4-i], b[4-i], carry are all "0") { carry = "0" result ="0" } if(i == 4) { return result } return addBinary(a, b, result, i+1, carry) + result; }
JavaScript
해당 코드에서는 2진수를 다루고 있지만, 2진수를 다루는 것이 포인트가 아니다.
2진수로 바꾼 후에 가장 아래자리 수 부터 차례대로 규칙에 따라 변경해 나갈 수 있어야 한다. 위에서 모든 코드를 작성하지는 않았으니 직접 작성해보는 것도 좋다.
해당 문제가 아주 특별한 상황이라고 생각할 수 도 있다. 하지만 우리가 작성하는 비즈니스 코드를 이러한 관점에서 바라보지 않았기 때문에 그렇게 느끼는 것은 아닐까? 적어도 내겐 키보드에서 물러나 펜을 쥐는 습관은 코드의 질을 높이는데 도움을 주었다.

기술의 근간

많은 기술들은 수학에 기초를 둔 것들이 많다. 때문에 수학을 잘 알고 있다면, 그 기술에 대해서 더 깊은 이해를 할 수 있다. 아래는 그 중 몇가지 예제를 소개한다.

RDB

SET과 같은 자료형이나, 관계형 데이터베이스등은 집합과 논리에 근거하여 만들어졌다. 이 때문에, 그 기술에 근본에 좀 더 다가갈 수 있고 이는 가장 기술친화적인 로직을 구현 할 수 있게 도와준다. 관계형 데이터베이스 좀 더 이해하기 에서 집합과 논리를 근거로 어떻게 좋은 데이터베이스 구조를 만들 수 있는지 설명한다.

Encoding Format

인코딩, 디코딩과 여러가지 포맷등은 진수와 진법을 제대로 이해하고 있다면 더 폭넓은 이해를 도와준다.
예를 들어 웹에서 img 태그를 사용할 때 바이너리 파일 형식이 아닌 base64를 통해 이미지를 그릴 수 있다. base64는 64진수를 나타내는데 이는 262^6으로 컴퓨터가 문자를 읽는 최소 크기인 바이트 282^8보다 4bit씩 남는 비트가 생긴다. 때문에 base64로 이미지를 표현하는 경우, 낭비하는 비트때문에 바이너리 이미지보다 크기가 더 크다.

제어 조건과 논리&집합 법칙

우리가 사용하는 if(제어)문은 논리 법칙 혹은 집합 법칙과 일치한다.
// 교환 법칙 A && B == B && A // 결합 법칙 A && ( B && C) == (A && B) && C // 분배 법칙 A && ( B || C ) == (A&&B) || (A&&C) // 드모르간의 법칙 !(A || B) == (!A && !B)
JavaScript
이러한 규칙을 잘 이용하면 제어 조건을 자유자재로 다룰 수 있기 때문에 Lazy Evaluation(지연 평가)등 유리한 연산을 하는 제어를 만들 수 있게 된다.

자료 구조

많은 자료구조는 수학에서 가져왔다.
Vector ( 벡터 )
컴퓨터 과학에서 벡터는 크기와 방향을 가진 다차원 행렬으로 사용된다.
이 때, 방향을 표현하기 위해 [0,0]에서 시작한다고 가정하여 사용한다.
예를 들면 [3,3]은 1사분면 방향으로 x축 3, y축 3만큼의 힘으로 이동한다.
벡터는 항상 같은 속성의 크기를 가진다. 이 말은 즉슨 벡터 내의 엘리먼트들은 모두 같은 타입을 가진다는 의미이다.
이러한 정형적인 타입 + 여러 차원의 데이터를 동시에 다루는 성질 때문에 스칼라 곱을 통해 가중치를 계산하는 등 머신러닝 진형에서 Featrue Vector 로 부르며 자주 사용된다.
Tuple ( 튜플 )
중복이 존재하는 셀 수 있는 수량의 순서 있는 열거이다. 일반적으로 집합(Set) 과 비교된다.
또한 Vector와 달리 여러 타입을 허용한다.
Set ( 집합 )
중복을 허용하지 않는 무한하고 순서가 없는 열거형이다. 자료 구조 뿐만 아니라 관계형 데이터베이스에도 이러한 특징을 이용한다.
기타 MAP, DICTIONARY등은 수학적 함수( 정의역, 공역이 있어 정의역의 각 원소를 정확히 하나의 공역 원소에 대응시키는 것)를 표현한다.

특별한 프론트엔드 개발자

위에서 수학 공부가 한다고 해서 당장에 할 수 없는 것들을 할 수 있게 되진 않기 때문이다. 라고 말했지만, 해당 챕터에서는 예외다.
웹에서의 UI는 CSS라는 아주 선언적인 기술 덕분에 다른 영상 처리와 다른 점이 많지만 근본적으로는 Graphics라는 사실이다. 그리고 Graphics는 어느 좌표에 어떤 값을 할당할 것인지에 대한 수학이 아주 중요한 영역이다.
특히 WebGL과 같은 기술이 점점 일반화되는 시점에서 수학을 공부하는 것은 프론트엔드 개발자에게 완전히 새로운 것을 표현할 수 있게 도와줄 것이다.
아래는 언제봐도 멋진 interactive developer 김종민님의 Leon Sans
또한 애니메이션을 다루는 컴포넌트들을 추상화 하는 것 역시 많은 수학적인 개념을 필요로 한다.
대표적으로 보간(Interpolation)과 같은 개념은 정규분포(gaussian distribution)를 이용한 Kriging 기법등과 같은 완전히 수학적인 공식을 이용해야 하는 경우가 많다.
아래와 같이 여러 애니메이션 라이브러리에서 보간과 같은 개념이 사용된다.
이미지 역시 2차원 벡터에 여러 스칼라 곱을 해서, 새로운 이미지를 만들어내는데 사용된다.
예를 들어 위의 식에 2차원 배열을 적용하면 Gaussian Blur 처리를 할 수 있다.

마지막으로

수학 공부를 하기 전에는 꽤 부정적인 생각이 많았다. 알고리즘을 꺼려하는 편이기도 하고, 컴퓨팅 파워의 향상으로 성능을 따지는 로직이 크게 무의미하다고 느껴 왔기 때문이다.
하지만 공부를 한 이후로 좋은 로직 이상으로, 이해하기 좋은 로직을 짤 수 있게 된 것 같다. 귀납적인 코드들은 대체로 왜 이렇게 짠 것인지 이해하기 어려운 반면, 연역적인 코드는 의도가 명확하고 불필요한 코드들이 없는 편이기 때문이다. 덕분에 더 나은 코드에 대해서 역시 돌아볼 수 있는 계기가 되었다.
뿐만 아니라, 익숙한 기술들에 대해서 더 깊게 이해하는 시간을 가질 수 있었고 생각의 폭 자체가 넓어진 느낌이다.
또 수학공부로 수식에 대한 자신감도 생겨서, 영상처리나 복잡한 애니메이션도 구현해보고 싶다는 생각도 들었다.