본문 바로가기

Programing

[생각] 패러다임과 프레임 그리고 멱등성

인용

패러다임(paradigm): 어떤 한 시대 사람들의 견해나 사고를 근본적으로 규정하고 있는 테두리로서의 인식의 체계, 또는 사물에 대한 이론적인 틀이나 체계를 의미하는 개념

프레임(이론): 틀이라는 의미가 추상적으로 확대되어 생각의 틀을 가리키는 용어(심리학적 프레임 등)로도 쓰인다.

서론

올해 중반 Effective Java 3/E이 부서내 읽는 분위기가 달아올랐다. 심지어 점심시간 스터디 그룹까지 생겨날 정도였다.

스터디에 참여를 하지는 않았지만 궁금해서 스터디에 임시로 참여해서 의견을 같이 나누는 시간을 가졌다.

스터디를 마치고 든 생각은,

1) 이펙티브 시리즈라는 것이 좋은 책이라는 점에 대해서는 이견이 없지만

2) 책을 읽고 나서 여기에 있는 내용에 대해 맹목적으로 따르는 부작용

에 대해 생각하게 되었다.

 

올해 초(2019년 1월) 옆에서 같이 일하는 용혁님이 CustomBuilder<T>라는 추상 클래스를 만들었다.

엄밀히 말하면 빌더는 아닌 것 같았다. 이름은 Builder로 끝나고 있지만 생성자를 통해 객체를 전달받고 있었기 때문이다.

빌더를 만들 이유를 물어보니 이펙티브 자바를 읽던중 Builder 패턴이 나와서 실무에 적용을 했다고 하였다.

 

디자인 패턴이 필요해서 적용한 것이 아니고, 배운 것을 적용을 해보고 싶어서 디자인을 한 것이 이유였다.

Spring Batch의 멱등성 유지하기 ?

2019년 9월 29일 Slack에서 'Spring Batch의 멱등성 유지하기' 제목의 글이 공유를 받았다.

다음과 같은 댓글이 달렸다.

P: 이걸 멱등성이라고 하기엔.. 너무 포장했네요
C: 제목만 보고 몇번을 실행해도 문제되지 않을 배치 디자인 방법과 기술을 제안할 줄 알았는데 날짜를 파라메터로 전달하는 내용일줄은ㅎㅎ
U: 멱등성과는 무관하지만, 제어할 수 없는 코드가 내부에 있는 건 매우 좋지 않은 코드죠.
M: 블로그 제목이 잘못되었거나 예시가 잘못된 것 같아요.

해당 글을 읽고 보니 글을 작성한 분은 멱등성(冪等性)이라는 용어를 글에 꼭 등장 싶었던 것 같았다.

마치 서론에서 Builder를 적용한 것 처럼 말이다.

멱등성이란?

영어로는 idempotent 라고 하고 수학이나 전한학에서 연산의 한 성질을 나타내는 것으로 연산을 여러번 적용하더라고 결과가 달라지지 않는 성질을 의미한다.

단항연산(함수)라면 아래와 같은 수식이 성립하게 된다.

f(f(x)) ≡ f(x)

왜 글에서 멱등성이 어색할까?

결론부터 이야기하면 멱등성에는 시간이라는 개념을 포함하지 않기 때문이다.

절댓값으로 변환을 하는 abs라는 함수를 예로 들어보자.

'절댓값이라는 개념'이 변경되지 않는다는 조건하에서는 오늘 실행(t1)되나 내일(t2) 실행되나 천년(t1000) 후에 실행되나 아래의 식은 성립하게 된다.

abs(abs(x)) ≡ abs(x)

시간이라는 차원을 수식에 같이 추가를 해서 표현을 하면 아래와 같다.

abst1(x) = abst2(x) = abst1000(x)

따라서 abs(x)는 시간과 독립적이다. 수학에서는 직교성(Orthogonality)을 갖는다고 이야기한다.

문제는

해당 글에서 멱등성이라는 용어의 등장이 어색한 이유는 해결하려는 문제 자체에 시간이 포함되어 있다는 것이다. (직교하지 않음)

그럼에도 시간에 따라 동일한 결과를 내고 싶어하여 애플리케이션에 존재하는 시계(Clock)을 떼어 외부로 옮기는 작업을 하였다.

그리고 시계가 없어진 애플리케이션은 멱등하게 바뀌었다고 공표한다.

그렇다면 해결하려는 문제는 이전과 동일할까?

다른 예 (IP 구하기)

좀 더 쉽게 이해하기 위해 다른 예를 들어보자.

실제 웹에는 자신의 공인 IP를 확인하기 위한 서비스가 많이 제공된다.
사용자를 위한 형태도 있고, 컴퓨터에서 처리하기 쉽도록 Restful API 형태의 제공도 한다.

 

https://api.ipify.org/?format=json 라는 URL을 HTTP GET 요청을 한다고 치자.

그러면 아래와 같은 JSON 형태의 응답을 받는다.

{"ip":"172.217.26.4"}

이 HTTP GET 요청은 멱등성이 유지되는 것일까?

혹시 내 MacBook Pro만 그런 것이 아닐까 생각이 든다. 옆자리 사람에게 테스트를 부탁한다.

동일한 값이 나온다. 그렇다면 멱등일까?

 

시애틀로 출장을 간다.

위의 웹서비스가 생각이 나서 테스트를 해보았다.

그런데 값이 바뀌었다.

{"ip":"156.74.181.208"}

이런 멱등성이 깨진걸까???

RFC-7231 (Hypertext Transfer Protocol (HTTP/1.1))

HTTP/1.1 RFC에 보면 4.2.2에 Idempotent Methods 라는 항목이 있다.

A request method is considered "idempotent" if the intended effect on the server of multiple identical requests with that method is the same as the effect for a single such request. Of the request methods defined by this specification, PUT, DELETE, and safe request methods are idempotent.

특정 서버에 대해 여러 동일한 요청이 단일 요청에 대한 효과와 동일한 경우 해당 메서드는 "멱등(idempotent)"으로 간주합니다.
이 RFC에서 정의하고 있는 요청 메서드들 중에 PUT, DELETE, 기타 안전한 메서드(Safe methods)들은 멱등입니다.

RFC 문서 상에는 PUT과 DELETE + Safe method 에 대해서만 멱등으로 정의하고 있다.

따라서 GET이 멱등한지 여부는 Safe methods하는지에 따라 달려있다.
위의 IP의 케이스의 경우에는 항상 동일한 값을 가져오지 않으므로 Unsafe 한 method이다.

 

가끔 RESTful API에 대해 아래와 같이 정리한 표가 많이 웹상에 돌아 다닌다.

HTTP GET을 멱등이 아니게 구현한 경우들이 있다.

GET나 HEAD의 경우 서버의 상태를 바꿔놓는 것이 아니기에 Safety 한 속성을 가져야 한다.

하지만 역사를 되돌아 보면 예전의 GET https://api.del.icio.us/posts/delete처럼 Unsafety 한 경우가 있다.

stackoverflow에 있는 표를 옮겨오면 아래와 같다.

+---------+------+------------+
| Method  | Safe | Idempotent |
+---------+------+------------+
| CONNECT | no   | no         |
| DELETE  | no   | yes        |
| GET     | yes  | yes        |
| HEAD    | yes  | yes        |
| OPTIONS | yes  | yes        |
| POST    | no   | no         |
| PUT     | no   | yes        |
| TRACE   | yes  | yes        |
+---------+------+------------+  

멱등하지 않는 것을 멱등하게 만든다면???

IP 결과가 장소에 따라 달라진다.

이것을  'Spring Batch의 멱등성 유지하기' 의 방법으로 해결해보자. myip 파라미터를 추가하는 것이다.

curl https://api.ipify.org/?format=json&myip=58.227.3.5
{"ip":"58.227.3.5"}

와, 이제 입력 받은 IP만 출력이 된다!!!

그리고, 어느 기기이든, 어떤 장소이든 동일한 값을 받는다!!!!

그러면서 서비스의 목적(현재 네트워크의 공인 IP를 받는 것) 또한 잃어버렸다.

마무리

결론은 애초에 멱등이 아닌 것을 멱등으로 만드는 것은 본래의 서비스의 목적을 바꾸는 것이다.

만약 'Spring Batch의 멱등성 유지하기' 에서 날짜를 파라미터로 받는 것 만으로 사용을 한다면 본래 최초의 코드와 다른 기능이 된다.

서비스 적인 전체적인 관점으로 보면 결국 clock의 위치 옮기기이다.

첫 번째 문제의 예시의 경우 아래와 같은 형상이 었다면...

clock 이 Spring batch 코드에 존재한다.

개선한 예시는 아래와 같은 모양이 될 것이다.

Jenkins로 clock이 옮겨갔다.

애플리케이션을 Spring batch 코드로 제한해서 보면 분명 변화하는 시간이 없어졌으므로 멱등으로 보일 것이다.

하지만 통합적인 관점으로 보면 단순한 Clock 옮기기이다.

물론 Clock을 어디에 두느냐가 많은 차이를 가져온다.

 

그래서 이 글의 제목은 'Spring Batch에서 Temporal Decoupling하기' 정도가 적합하지 않느냐는 의견이다.

 

아마 동욱님은 멱등성이라는 패러다임(프레임)사랑에 빠져있는 게 아닌가 추측해본다.

"사랑하면 눈이 멀어 다른 것은 눈에 보이지 않으니" 시간만이 해결해 줄 것 같다.

 

---

2020-07-10 추가

조영호 님의 오브젝트(책)를 읽다가 '멱등성'을 대신할 적절한 용어를 찾았다.

초판 기준으로 27쪽에 나온다.

책임의 이동(shift of responsibility) : 알기 쉬운 디자인 패턴(Design Pattern Explained: A New Perspective on Object-Oriented Design), 피어슨에듀케이션코리아(2003)