블로그 이미지
개발에 대한 내용을 주로 다루는 블로그입니다. 개인 개발 기록이므로 경우에 따라 맞지 않는 내용이 있으니 감안하셔야 합니다. bebeside77

카테고리

분류 전체보기 (50)
개발 (46)
기타 (3)
IT (1)
Total11,043
Today37
Yesterday5

달력

« » 2018.07
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31        

공지사항

설계, 개발을 하다보면 결정을 해야할 순간이 많은데,

최선의 의사결정을 하기 위해서는 고려해야할 것이 많다. 하지만 경우에 따라 직관적으로 선택하거나 기분에 따라 선택하기도 한다. 


최선의 의사결정을 위한 프로세스를 결정 시 적용해보면 좀 더 좋은 선택을 할 수 있지 않을까 한다.




- 내용 출처 : <<자신있게 결정하라>> 칩 히스, 댄 히스


어떻게 의사결정을 내려야 후회할 확률이 낮아질까?

연구결과 탁월한 결정을 하는데 최종 의사결정자의 직관이나 전문가 그룹의 분석보다 프로세스가 6배나 더  중요하다는 것이 밝혀졌다.


프로세스는 의사결정을 하기 위한 일종의 과정, 예를 들어 최종 의사 결정자가 선택하기 전에 반대 의견을 꼭 수렴해야 하는 제도가 있다는 것 등을 말한다. 아무리 분석이 좋다 하더라도 훌륭한 의사결정 프로세스가 없으면 무용지물 되는 경우가 많다.

반대로 적절한 프로세스가 있는 경우 그 분석은 의사결정에 매우 긍정적인 역할을 했다. 결국, 의사결정을 할 때 적절한 프로세스가 있느냐 없느냐에 따라 의사결정 수준이 달라진다는 것이다.


WRAP 프로세스


1. 선택안은 정말 충분한가? (Widen your options)

    - 하나의 선택안을 놓고 그것을 할 것인지 안 할 것인지를 결정하는 경우 52%가 실패

    - 2개 이상의 대안을 고려했을 경우 실패율이 32%로 낮아진다

    - 선택안을 늘릴수록 성공적인 의사결정 할 확률이 높아진다

    - 선택안을 늘리기 위해 주변에 조언을 구하거나 많은 독서를 하는 것도 필요하다



2. 검증의 과정은 거쳤는가? (Reality-test your assumptions?)

    - 확증 편향을 조심해야 한다

      - 확증 편향 : 실제 마음속으로는 이미 어느 정도 결정 한 뒤 그 결정을 뒷받침하는 정보만 선별 수집하려는 것

    - 자료 수집 시 객관성을 가져야하며 잠정적 선택에 반대되는 근거에 대해 적극적으로 알아야 봐야한다

    - 검증 시는 숲과 나무를 동시에 보아야 한다

      - 숲 : 이론, 통계, 전문가의 견해를 참조

      - 나무 : 현장에 직접 가거나 사람들과 접촉


3. 충분한 심리적 거리는 확보했는가? (Attain distance before deciding)

    - 순간적인 욕심, 욕정, 불안, 분노 등이 최악의 결정에 이르게 한다

    - 내 결정이 아니라 친한 친구의 결정이라고 상상해보는 것도 도움이 된다 (타인의 결정에 대해서는 감정 배제를 잘함)



4. 실패의 비용은 준비했는가? (Prepare to be wrong)

    - 최악의 상황을 상상하고 플랜B, 플랜C 더 나아가 플랜Z까지 생각해 놓을 필요가 있다

    - 실패 시 그것을 빠르게 복구할 수 있음



WRAP 프로세스를 모든 의사결정에 적용할 필요는 없지만 5분 이상의 고민이 필요한 경우에 사용하면 좋다.

WRAP 프로세스를 한다고 해서 매번 최상의 선택이 되는 것은 아니다.




Posted by bebeside77

스프링 배치 잡을 실행할 때 다음과 같은 오류가 발생하는 경우가 있다.


cannot change the ExecutorType when there is an existing transaction


이 에러는 존재하는 트랜잭션이 있을 경우 MyBatis의 ExecutorType (SIMPLE, BATCH, REUSE) 을 변경할 수 없다는 의미이다.


스프링 배치 잡에서만 날 수 있는 오류는 아니고 MyBatis를 사용하고 트랜잭션 설정된 부분이 있다면 발생할 수 있을 것이다.


트랜잭션으로 묶여있는 동안은 배치 잡 내에서 동일 데이터 소스에 대해서는 동일 SqlSessionTemplate을 사용하게 될 것인데,

ExecutorType은 SqlSessionTemplate에 종속적인 설정 값이다.


해결하는 방법은 상황에 따라 다르겠지만 만약 동일 ExecutorType을 사용하도록 맞추려고 한다면,

다른 ExecutorType을 사용한 DAO에 동일한 ExecutorType을 가진 SqlSessionTemplate을 사용하도록 설정하면 된다.


예를 들어서, BATCH 타입으로 트랜잭션이 수행되다가 SIMPLE 타입을 사용하는 DAO 메소드 하나가 실행되어 에러가 발생했다면,

그 DAO에 다음과 같이 설정해주면 된다.


<bean id="personDAO" class="com.sheerheart.dao.PersonDAO">

<property name="sqlSessionTemplate" ref="sqlSessionTemplate-batch" />

</bean>


<bean id="sqlSessionTemplate-batch" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">

<constructor-arg index="0" ref="sqlSessionFactory"/>

<constructor-arg index="1" value="BATCH"/>

</bean>


만약 MapperScan을 사용하고 있어서 DAO 인터페이스만 존재하는 상황이라면 다음과 같이 하면 된다.


<bean id="personDAO" class="org.mybatis.spring.mapper.MapperFactoryBean">

<property name="mapperInterface" value="com.sheerheart.dao.PersonDAO"/>

<property name="sqlSessionTemplate" ref="sqlSessionTemplate-batch"/>

</bean>


<bean id="sqlSessionTemplate-batch" class="org.mybatis.spring.SqlSessionTemplate" destroy-method="clearCache">

<constructor-arg index="0" ref="sqlSessionFactory"/>

<constructor-arg index="1" value="BATCH"/>

</bean>


만약 같은 트랜잭션에 묶이지 않아도 되는 것이라면 트랜잭션에 묶이지 않도록 제외 처리하는 등의 방법이 있다.

Posted by bebeside77

사이트 서버와 모바일 API 서버는 기술적인 부분에서 비슷한 부분이 많지만 API 서버라는 특성 때문에 조금 신경 써야할 부분도 있기에 API 디자인 시 참고할 만한 내용들을 찾아보고 정리한 내용이다.


API 서버는 한번 API 클라이언트에게 나가고 나면 변경하기가 힘들다.

사이트는 클라이언트 코드와 서버 코드 모두 서버에서 제공하기 때문에 부분을 동시에 변경하는 것이 가능하지만,

같은 경우에는 일반적으로 스토어를 통해서 배포되기 때문에 동시에 변경할 수도 없고

사용자가 업데이트 하지 않으면 계속해서 버전을 사용할 수도 있다. 앱을 업데이트하지 않으면 사용할 없도록 강제 업데이트하는 방법이 있긴 하지만 되도록이면 피해야 한다.



REST 준수하는 것은 좋지만 그것을 목표로 해야하는 것은 아니다.


API 페이로드를 디자인할 일관성, 완성도에 신경을 쓰도록 하라.

일관성은 API를 사용하는 개발자가 무엇을 기대해야 할지 아는 것이다. (가장 적게 놀람의 원칙)

완성도는 적은 roundtrip 의미한다. 3G 환경에서 HTTP latency 1초까지 걸릴 있다.


API DB 대한 CRUD 인터페이스가 아니다

더 높은 추상 레벨의 Facade이다. 객체나 메소드가 아닌 서비스 관점에서 생각해야 한다.

그러면 어떻게 시작해야 하는가? 대부분의 모바일 API 화면에 보여줄 정보를 가져오기 위해 사용된다. 데이터로부터가 아니라 UI에서부터 시작해야 한다.

    1. 화면을 구상한다.

    2. 보여줄 엔티티들은 무엇인지

    3. 엔티티 모델을 디자인한다.

    4. 서비스를 디자인한다.



일관성있게 데이터를 제공한다.

 

"person": {

"id": 1234,

"name": "Fred",

"lastname": "Brunel"

}

 

<좋지 않은 >

"book": {

"Name": "Steve Jobs",

"author": "Walter",

"lenders": = [{

"person_id": 1234,

"person_name": "Fred",

"person_lastname": "Brunel"

}]

}

 

<좋은 >

"book": {

"name": "Steve Jobs",

"author": "Walter",

"lenders": = [{

"id": 1234,

"name": "Fred",

"lastname": "Brunel"

}]

}



대부분의 일반적인 항목들을 정규화 하라.

불필요한 요청을 하지 않아도 되게 하자.

 

<좋지 않은 >

"result": {

"categories": [{ "id: 2 }],

"images": [{ "id": 2323 }]

}

 

<좋은 >

"result": {

"categories": [{

"id: 2,

"name": "food"

}],

"images": [{

"id": 2323,

"url": "http://image.com/a.png"

}]

}

 

예를 들어 사용자가 어떤 데이터를 요청하기 전에 로그인을 해야한다고 하자. 다음 단계로 진행하는 방법을 생각해볼 있다.

    1. 클라이언트로부터 인증 정보가 제공되고 유효하다면 API 세션 토큰을 전달한다.

    2. 클라이언트가 세션 토큰과 함께 데이터 요청을 한다

 

하지만 클라이언트가 인증 정보와 데이터 요청을 함께 보내고 서버는 데이터와 세션 토큰을 전달함으로써 한번의 요청만 하는 방법도 있다.

이렇게 하면 가지 사용법을 모두 지원할 있도록 개발해야해서 유지보수 비용이 발생할 있다. 하지만 만약 본인이 사용하기 위한 API 개발하는 것이라면 적용할만 하다.



앱에서 다른 써드파티 시스템들과 연동하게 하지말고 서버에서 취합하는 방식을 사용해라.

서버가 많은 배터리와 대역폭 그리고 데이터들을 가지고 있다.



빠르게 만들어라.

    - 배치 요청: 복수 operation들을 보내고 한번에 결과를 받는 방법

    - 네트워크가 중요하다면 별도 프로토콜을 정의하는 방법: HTTP 프토코콜 대신 별도의 Binary 프로토콜을 만든다.



버저닝을 하는 것에 대한 고려 

기반의 앱은 버저닝이 크게 중요하지 않지만 네이티브 앱은 중요한 문제이다. API 기능이 추가, 변경, 삭제되는 일이 발생하게 되는데 버저닝을 통해서 구버전 API 사용하는 앱에서도 호환성을 지킬 있다.


여러 자료들을 본 결과 버저닝이 필요한 것인지, 버저닝에 자유로운 API를 만드는게 좋은지에 대한 논란이 분분한 것 같다.

만약 버저닝을 한다면 다음 정도의 방법이 있다.

 

[버저닝 방법]

 

 

이름을 신중하게 지어라.

API 프로퍼티, 파라미터, 메소드의 이름은 클라이언트가 API 이해하는데 많은 영향을 준다. 실제 코드가 어떠하든, API 이해하고 동작을 예상하는데 이름을 영향을 준다. 잘못된 이름은 혼동을 주고 혼동은 실수를 유발하며 실수는 버그를 만든다.

 



[참고자료]

Posted by bebeside77

최근에 달린 댓글

글 보관함