'2018/02'에 해당되는 글 7건

  1. 2018.02.28 The multi-Armed Bandit Problem이란? #2
  2. 2018.02.28 The Multi- Armed Bandit Problem이란? #1 [출처] The Multi- Armed Bandit Problem이란?
  3. 2018.02.28 더치 옥션 (Dutch auction)
  4. 2018.02.28 비커리 경매(Vickery Auction)
  5. 2018.02.28 CTR (Click-through rate)
  6. 2018.02.28 Java 8 - Interface의 변화
  7. 2018.02.22 왜 자바에서 static의 사용을 지양해야 하는가? 6

The multi-Armed Bandit Problem이란? #2

광고/용어 2018. 2. 28. 11:41

Multi-armed 이해하기 위해 one-armed 알아봅시다가장 흔하게 예로 들어지는 one-armed 슬롯머신입니다카지노에서   있는 슬롯머신에는우측에 당길  있는  레버가 하나 달려 있습니다.  (기계식 슬롯머신은 영화나 박물관에서   있고 요즈음은 전자식으로 버튼을 누르는 슬롯머신을 쓰고있기는 합니다.)  레버를 잡아 당겼다 놓으면 게임이 시작됩니다

 실제로 카지노에서 빠른 시간 안에 많은 돈을 슬롯머신에서 잃을  있습니다만약에  슬롯머신에서 돈을   있는 기회가 50:50라고 한다면 실제로 돈을 잃을 기회도 50: 50 것입니다하지만 카지노에서 슬롯머신에 bug 넣고 사람들은 실제로 50%보다  빠른 속도로 돈을 잃게 되며  기계가 돈을 강탈해 가기 때문에   레버를 bandit(도둑강도)라고 부르는 이유가 됩니다.
 그러면 multi-armed bandit 무엇일까요Multi – armed bandit problem이라는 것은 예를 들면  사람이 5대의 슬롯머신 세트를 play해야 하는 상황을  있습니다 5대의 슬롯머신에서 최소한으로 돈을 잃고 최대한으로 돈을따야 합니다. 5대의 슬롯머신을 100, 1000 반복되는 게임을 하다 보면 어떤 기계에서 돈을  따게 되고 어떤 기계에서 돈을  잃을  경험적으로   있습니다하지만 가지고 있는 돈은 한정이 되어 있으니 한없이 게임을 반복할   없습니다.
 
 5대의 슬롯머신을 M1, M2, M3, M4, M5라고 하고   각의 기계는 default 값이 달라 돈을 잃고 따는 확률이 다르다고 가정해 봅시다하지만 게임을 하는 사람은 사전에 어떤 기계에서 돈을  많이   있는지는   없습니다따라서 게임을 하는 사람은 빠른 시간 안에 가장 돈을 많이   있는 기계를 알아내야 합니다. M1부터 M5까지 슬롯머신마다 각각의 distribution 값을 보게 되면 어떤 기계가 가장 돈을 많이   있는 기계인지   있습니다 사실만  알게 된다면 게임을 하는 사람은  기계에만 계속 배팅을 하고 가장 이득이되는 결과를 갖게  것입니다.
 하지만 어떤 기계가 좋은 결과를 보여주는지 찾는 동안에도 계속해서 돈을 써야 하고 잃어야 합니다어떤 기계에서 돈을   있는   아는 데까지 시간이 많이 걸린다면 확률이 낮은 기계에 돈을 계속 쓰게 되고  사이에 가진 돈을 모두 잃게   모릅니다.

 따라서 이렇게 슬롯머신 게임을 하면서  가지의 개념이 필요하게 됩니다
Exploration(탐험하기) exploitation(뽑아먹기)
1)      어떤 기계에서 가장 돈을 많이   있는지 빠른 시간 안에 알아야 한다(exploration)
2)      동시에 현재 알고 있는 가장 돈을 많이   있는 기계에서 최대한 빨리 돈을 계속 따야 한다(exploitation)
 
또한 여기서 regret이라는 수학적 개념이 나오게 됩니다.
한쪽은 optimal machine 돈을 계속 넣어서 돈을 따게 되었지만 다른 한쪽은non-optimal machine 돈을 계속 넣어서 많은 돈을 잃게 되었다면 best outcome non-best outcome 사이의 차이가 regret개념이 됩니다.
 Optimal machine 찾기 위해 다른 기계들을 exploration하는데 쓰이는 비용을 opportunity cost라고 하며 다른 non-optimal machine들을 explore하는 시간이 길면 길수록 높은 reget값을 가질  있습니다빠른 시간 안에 explore하면서 sub-optimal machine 찾고(exploration)   기계에서 계속 돈을 따면서( exploitation) 최소한의 시간 안에 optimal machine 찾아 내야 합니다
(짧은 시간 안에 찾은 sub-optimal distribution 정말 optimal distribution인지 검증이 필요합니다섣부른 판단으로 sub-optimal optimal이라고 판단할 수도 있습니다
 
정리를 한다면The multi-Armed Bandit model 목적은 best one 찾고(exploration)  best one에서 돈을 따고(exploitation) best one 찾는 시간을 최소화 하는 것입니다.


:

The Multi- Armed Bandit Problem이란? #1 [출처] The Multi- Armed Bandit Problem이란?

광고/용어 2018. 2. 28. 11:40

 Reinforcement learning 쉬운 예를 들어본다면 robot dog에게 걷기 연습을 시키는 algorithm입니다. Robot dog에게 우측 앞발을 움직이고 다음에 좌측 뒷발을 움직이고  다음으로 좌측 앞발을 움직이게 프로그래밍을 하고 실제적으로 연속적으로 수행하도록   있습니다 다른방법으로  Reinforcement learning algorithm 이용하여 robot dog 걷도록 training시킬  있습니다기본적으로 robot dog에게 모든 가능한 action tool 들에 대해 알려줍니다이렇게도 움직일  있고 저렇게도 움직일  있다는 정보를 줍니다그리고 robot dog 목표는 앞으로 나아가는 것이라고 알려줍니다앞으로 나아가는  순간마다 reward 받고 넘어지는 순간마다 punishment 받습니다당근이나 간식을 주는 것은 아니고 algorithm에서  reward  1이고 punishment 0 입니다기본적으로 robot dog 모든 가능한 random sets action 시도하게 되고  순간 1  0  평가를 받게 됩니다. Machine 이러한good action들을 기억하게 되고 반복함으로써 실제로 개가 걷는 것처럼 앞으로 걸을  있게 됩니다.
 
Multi-Armed Bandit Problem 무엇일까요?
기본적인 가정을 두가지 해보도록 하겠습니다.
1)      우리는 세상에 대해  모른다.
2)      세상은 계속 변한다.
Machine learning에서 지도학습이란  모르는 세상에 대해 기존의 지식을 training하고 일반화를 통해 최적화된 모델을 만드는 것이지만  모든 일반화된 모델 역시  번째 가정 세상은 계속 변한다에 의해 지속적으로 업그레이드 되어야 하는 경우가 발생하게 됩니다.
이때 필요한 중요한 개념은
Exploration(탐험하기) : 최적 안을 결정하기 위해 다른 안들을 계속 평가하는 
Exploitation( 뽑아먹기)최적 안이 나왔다면 이곳으로 사용자를 몰아주고 최대의 이익이 나올  있도록 하는 .
반복적으로  검증가능한 현상을 과학이라고 부르지만 비즈니스 환경 등에서는 계속되는 변화 속에 있고 추세의 변화를 빠르게 찾아낼 필요가 있게 됩니다얼마만큼의 시간과 재화의 투자를 exploration(탐험하기) 몰아주고 얼마만큼의 시간과 재화를 exploitation(뽑아먹기) 몰아주어야 이익이 최대가  것인가를 알고 또한 시간의 흐름에 따라 얼마의 비중으로 exploration exploitation 비율을 바꾸어갈지 판단해야 하며 이는 어려운 문제가 됩니다이와 같은 딜레마의 대표적인 예가 multi-armed bandit problem입니다.
 


'광고 > 용어' 카테고리의 다른 글

The multi-Armed Bandit Problem이란? #2  (0) 2018.02.28
더치 옥션 (Dutch auction)  (0) 2018.02.28
비커리 경매(Vickery Auction)  (0) 2018.02.28
CTR (Click-through rate)  (0) 2018.02.28
:

더치 옥션 (Dutch auction)

광고/용어 2018. 2. 28. 10:43

두산백과

더치 옥션

[Dutch auction음성듣기]

요약 매도자가 최고 호가로부터 점차 가격을 낮추어 가다가 매수 희망자가 나오면 최초의 매수 희망자에게 매도하는 경매 가격결정 방법.

네덜란드식 경매라고도 한다. 일반적으로 경매는 최저 호가로부터 점차 가격을 높여 가다가 최고 호가의 매수 희망자, 곧 마지막 매수 희망자에게 매도하는 방식을 취한다. 그러나 더치 옥션은 이와는 반대로 매도자가 최고 호가로부터 점차 가격을 낮추어 가다가 매수 희망자가 나오면 최초의 매수 희망자에게 일괄 매도하는 가격결정 방법이다.

이는 채권을 매각할 경우에도 마찬가지로 적용된다. 즉 경매에 참여한 매수 희망자가 자신이 떠안을 수 있는 물량과 가격 조건을 제출하되, 최저 금리를 제시한 물량부터 차례로 채우다가 마지막 물량을 떠안은 매수 희망자가 제시한 금리로 물량을 떠안는 제도를 말한다. 다시 말해 채권을 입찰에 부치되 경매 참여자가 써 낸 금리 가운데 최고치로 발행액 전액을 매각하는 방식이 더치 옥션이다.

1997년 국제통화기금(IMF외환위기 당시 외국 금융기관(채권은행)들은 한국의 단기외채 250억 달러를 중장기로 전환할 경우 적용하는 금리를 이 방식으로 결정하자고 제안하였으나, 한국 정부에서는 당사자 협의방식을 주장해 더치 옥션은 수용되지 않았다.

[네이버 지식백과] 더치 옥션 [Dutch auction] (두산백과)


출처 - http://terms.naver.com/entry.nhn?docId=1222336&cid=40942&categoryId=31721


:

비커리 경매(Vickery Auction)

광고/용어 2018. 2. 28. 10:42

잠재적 구매자는 입찰가를 비밀리에 제출하고, 가장 높은 가격을 제시한 사람이 경매에서 이기지만 자신의 입찰가가 아니라 제출된 가격 중 두번째로 높은 가격을 지불한다.

:

CTR (Click-through rate)

광고/용어 2018. 2. 28. 10:26

클릭률

[Click-through rate]

약어CTR

온라인 광고의 노출횟수 대비 클릭 수를 의미한다. 배너광고가 노출된 횟수(Impression) 중, 실제 클릭을 통해 배너광고에 연결된 웹페이지(웹사이트)로 이동한 경우의 비율을 일컫는다. 어떤 온라인 광고의 웹페이지 게재 횟수(노출된 횟수, impression)가 100번이고, 그 광고 클릭 횟수가 1번이면 CTR(CTR=(클릭 수/ 노출된 횟수)×100)은 1%라는 얘기가 된다. 온라인 광고 효과를 측정하는 데 있어 CTR은 중요 지표다. 웹사이트의 방문자를 광고주가 원하는 최종 웹페이지까지 이동하도록 클릭을 유도하는 데 성공한 광고라면, 방문자의 호기심을 자극하는 데 성공했다고 볼 수 있기 때문이다.

현재 온라인상 광고 클릭률(CTR)은 대략 0.2%~0.3%로 매우 낮은 편이나, 아직 그 어떤 예측 분석 솔루션도 어느 광고 캠페인이 어떤 개인으로부터 최고의 클릭률을 유도할 수 있는지 식별하지 못한다. 광고 클릭 과정은 변덕스러우며, 대개 광고를 접할 당시 개인의 기분 과 요구사항이 반영되는 경우가 많다. 전반적으로 모바일 기기가 PC보다 더 높은 배너광고 클릭률을 기록했다. 안드로이드 기기의 평균 클릭률은 PC의 두 배로 나타나 전 세계적으로 안드로이드 기기에서 더 많은 매출이 발생했다.

반면, 미국과 유럽에서는 iOS 기기 매출이 안드로이드를 앞서는 것으로 조사되었다. 모바일 기기는 PC 사용량을 보완하여 추가적인 매출을 창출한다. 일례로 일요일에 발생하는 전자상거래 중 아이패드 내 구매율은 16% 더 높은 반면, 데스크톱 내 구매율은 10% 낮아진다고 발표했다. 또한 모바일 기기에서 가장 높은 평균 구매가는 호텔 및 렌터카 예약과 의류구매에서 발생했으며 각각 약 365달러, 209달러, 105달러(한화 약 36만원, 22만 원, 11만 원)로 조사되었다.


출처 - http://terms.naver.com/entry.nhn?docId=3586054&cid=59277&categoryId=59282


:

Java 8 - Interface의 변화

Language/JAVA 2018. 2. 28. 09:32

요즘 카이 호스트만의 코어 자바8로 Java 8을 공부하고 있다. 작년 초에 개발자로 전향하여 Java 8의 stream 같은 것을 매우 신기해하며 어깨너머로 배워 사용했었는데 알고보니 Java 8이 처음 출시된 것은 2014년 3월 18일이었다.(Java 릴리스 페이지 참고) 지금은 Java 9가 나오려고 몸을 들썩이는 중이다. Java 8을 제대로 공부도 해보지 않았는데 벌써 Java 9가 나온다고 하니 젊은 나이에 뒤처지는 것 같은 기분이 들었다. 이런 까닭에 황급히 서점에서 책을 사서 공부하는 중이다. 원저의 제목 Core Java for the Impatient가 내 상황에 잘 들어맞는 것 같다. 더 늦기 전에 Java 8을 공부하면서 중요하다고 생각하는 것들을 정리해보려고 한다.

인터페이스

객체 지향 프로그래밍에서 인터페이스는 기능의 생김새만 나타낸다. 인터페이스는 어떤 기능에 대한 추상이며, 실제 구현은 그 인터페이스를 구현하는 클래스에게 맡긴다. 해당 인터페이스를 사용하는 입장에서는 실제 클래스가 어떻게 구현되어 있는지 몰라도 인터페이스의 생김새에 따라 함수를 호출하기만 하면 된다. 마치 복잡한 시스템의 UI(유저 인터페이스)와 같다. 구글 검색 엔진은 복잡한 시스템이지만 사용자에게 보여주는 건 질의어를 입력하는 텍스트 박스밖에 없다.
구글 검색 엔진구글 검색 엔진

검색 엔진의 구현을 몰라도 검색을 할 수 있다(이미지 출처: 구글)


추상화가 잘되어 있다는 것은 (구글 검색 엔진처럼)객체의 필요한 기능만 드러내고, 복잡하고 굳이 드러내지 않아도 되는 내용들은 숨겼다는 것을 의미한다. 이전에는 이러한 인터페이스의 추상성을 철저히 지켰기 때문에 인터페이스가 어떤 상태(인스턴스 변수)나 구현된 메서드를 갖는 것이 불가능했다. 하지만 Java 8부터 인터페이스가 조금 더 유연하게 바뀌었다.

정적 메서드

기술적으로 Java에서 인터페이스에 정적 메서드를 추가하지 못할 이유는 없었다. 정적 메서드는 어차피 인스턴스와 관계가 없기 때문이다. 다만 정적 메서드도 구현된 메서드라는 점에서 인터페이스의 추상성을 해친다는 것이 문제였다. Java 8에서는 그러한 제약이 없어졌고, 인터페이스에 정적 메서드를 추가할 수 있게 되었다.(사실 이전에도 인터페이스에 정적 필드는 정의할 수 있었기 때문에 정적 메서드가 Java 8에 와서야 추가된 것은 조금 의아하다.) 기존의 제약을 깨고 정적 메서드를 추가한 것은 개발 편의성을 높이려는 시도로 보인다. Java 8 이전의 표준 라이브러리에서는 인터페이스와 관련된 정적 메서드들을 동반 클래스(companion class)에서 제공했다. 대표적인 예로 Collection 인터페이스와 Collections 동반 클래스가 있다.

// 인터페이스와 동반 클래스의 예.
Collection<String> empty = Collections.emptyList();

이제는 인터페이스에 바로 정적 메서드를 추가할 수 있기 때문에 동반 클래스를 따로 정의하지 않아도 된다. Java 8에 추가된 Stream 인터페이스는 유용한 정적 메서드들을 제공한다.

Stream<String> chosunKings = Stream.of("태조", "정종", "태종", "세종", "문종", "단종", "세조", ...);
Stream<String> southKoreaKings = Stream.empty();

기본 메서드(default method)

Java 8에서는 인터페이스에 기본 구현을 정의할 수 있게되었다. 기본 구현이 제공되는 메서드는 구현 클래스에서 구현하지 않아도 컴파일이 가능하다. 기본 메서드는 기존의 인터페이스에 메서드를 추가해야하는 경우에 아주 유용하다. 인터페이스가 변경되는 일이 없도록 프로그램을 잘 작성하는게 좋겠지만 변경이 불가피한 상황이 생길 수도 있다. 인터페이스에 메서드를 추가하면 해당 인터페이스를 구현하는 모든 클래스에서 추가된 메서드를 구현해야하기 때문에 문제가 생긴다. 구현 클래스가 9개라면 인터페이스까지 10개의 파일을 수정해야 한다. 하지만 추가되는 메서드의 구현이 대부분 동일하다면 인터페이스에 기본적인 메서드 구현을 정의하고 유별난 클래스만 수정해주면 된다. 연료 유형을 포함하는 Car 인터페이스를 예로 들어보자.

public interface Car {
String fuelType();
}

연료 유형에 따른 구현 클래스들도 있다.

public class DieselCar implements Car {
@Override
public String fuelType() {
return "DIESEL";
}
}

public class GasolineCar implements Car {
@Override
public String fuelType() {
return "GASOLINE";
}
}

자동 주행 차량에 발빠르게 대응하기 위해서 Car 인터페이스에 자동 주행 차량 여부를 확인할 수 있는 메서드가 추가되어야한다고 생각해보자. Car는 아래와 같이 변경되어야 한다.

public interface Car {
String fuelType();
boolean autodrive();
}

이 경우에 autodrive() 메서드는 기본 구현을 제공하지 않으므로 DieselCarGasolineCar에서 구현해줘야 한다. 하지만 기존 차량들은 자율 주행이 안될 것이기 때문에 아래와 같이 기본 구현을 제공할 수 있다.

public interface Car {
String fuelType();
default boolean autodrive() {
return false;
}
}

autodrive()는 FutureCar와 같은 유별난 클래스에서만 따로 구현해주면 된다.

public class FutureCar implements Car {
@Override
public String fuelType() {
return "SOLAR";
}
@Override
public boolean autodrive() {
return true;
}
}

인터페이스의 기본 메서드는 클래스의 계층을 좀 더 단순하게 만들어준다는 장점도 있다. Java 2부터 있어왔던 AbstractCollection은 Collection 구현 클래스들의 공통 기능을 제공한다. Java 8 이전에는 구현 클래스들의 공통 기능들을 묶기 위해 인터페이스와 구현 클래스 사이에 추상 클래스를 정의하는 것이 일반적이었다. 하지만 Java 8에 와서는 더 이상 추상 클래스를 추가할 필요 없이 기본 메서드를 정의할 수 있게 되었다. 이런 변화로 인터페이스와 추상 클래스의 경계가 모호해졌다는 느낌이 들지만 여전히 인스턴스 변수의 유무 차이는 존재한다.

기본 메서드의 충돌 해결하기

Java에서 하나의 클래스는 여러 인터페이스를 구현할 수 있다. Java 8 이전에는 여러 인터페이스가 같은 메서드를 갖더라도 어차피 구현은 클래스에서만 제공했기 때문에 문제가 되지 않았다. 하지만 Java 8에서 인터페이스들이 각각 동일한 메서드의 기본 구현을 제공하고, 클래스에서 충돌이 발생하는 메서드를 명시적으로 오버라이드 하지 않으면 컴파일러가 어떤 기본 메서드를 사용해야할 지 선택할 수 없기 때문에 문제가 발생한다. 책에 나와있는 예시를 살펴보자.

public interface Person {
String getName();
default int getId() { return 0; }
}
public interface Identified {
default int getId() { return Math.abs(hashCode()); }
}
public class Employee implements Person, Identified {
...
}

Person과 Identified 인터페이스는 getId() 기본 메서드를 정의하고 있고, Employee 클래스는 두 인터페이스를 구현한다. Employee 클래스에서 getId()를 오버라이드 하지 않으면 Employee inherits unrelated defaults for getId() from types Person and Identified 라는 컴파일 에러가 발생한다.

한 쪽에서 기본 메서드를 구현하지 않으면 문제가 해결될까? Identified를 아래와 같이 기본 메서드 구현을 하지 않도록 바꾸고 컴파일 해보자.

public interface Identified {
int getId();
}

될 것 같지만 메시지가 Employee is not abstract and does not override abstract method getId() in Identified 라고 바뀔 뿐 여전히 컴파일은 되지 않는다. Person과 Identified 인터페이스가 동일한 메서드를 갖고 있긴 하지만 컴파일러 입장에서는 두 개가 정말 같은 목적의 메서드인지 알 길이 없다. 따라서 같은 모양의 메서드지만 두 메서드를 다른 것으로 보고 클래스가 Identified를 구현하지 않았다고 판단한다.(개인적으로는 이것이 일관성이 부족하다고 생각하는데 그 이유는 두 인터페이스 모두 기본 메서드를 구현하지 않는 경우에는 충돌이 일어나지 않기 때문이다.)

가장 좋은 해결 방안은 충돌이 나는 경우를 만들지 않는 것이다. 두 인터페이스가 동일한 메서드를 갖고 있다면 인터페이스 간에 상속 관계가 있지는 않은지, 메서드 이름을 너무 포괄적으로 정한 것은 아닌지 따져보고 충돌 상황을 피하는 게 좋다.

메서드 이름이나 기본 메서드 구현을 포기하지 않고 컴파일 에러를 해결하는 방법은 아래와 같다.

클래스에서 충돌 메서드 구현

가장 단순한 방법으로 클래스에서 충돌 메서드의 구현을 덮어 버리는 것이다. 이 때 클래스에서 구현을 새로 할 수도 있지만 어느 한 쪽의 기본 메서드를 사용할 수도 있다.

public class Employee implements Person, Identified {
@Override
public int getId() {
// Person의 기본 메서드를 사용하고 싶은 경우.
// Identified의 기본 메서드를 사용하려면 Identified.super.getId()를 반환한다.
return Person.super.getId();
}
}

인터페이스간 상속

Person 인터페이스가 Identified를 상속받도록 하면 Employee에 구현 메서드가 없어도 문제를 해결할 수 있다. 하지만 이런 결정을 하기 전에 인터페이스 사이의 관계를 잘 고려해야한다.

public interface Person extends Identified {
String getName();
default int getId() { return 0; }
}
public interface Identified {
default int getId() { return Math.abs(hashCode()); }
}

이렇게 하면 Employee는 결국 Person의 기본 메서드를 사용하게 된다.


출처 - http://happinessoncode.com/2017/04/19/java8-changes-in-interface/

'Language > JAVA' 카테고리의 다른 글

왜 자바에서 static의 사용을 지양해야 하는가?  (6) 2018.02.22
Generic 메서드  (0) 2017.10.20
자바 람다식(Lambda Expressions in Java)  (0) 2016.09.09
자바 JVM 정리(Java Virtual Machine)  (0) 2016.08.05
GC  (0) 2016.08.05
:

왜 자바에서 static의 사용을 지양해야 하는가?

Language/JAVA 2018. 2. 22. 11:10

자바에서 데이터를 가공하거나 특정 메서드를 수행할 때 새로운 클래스를 만들어서 이를 인스턴스화 해서 쓸건지 아니면 static 으로 쓸건지 고민하게 될 때가 있다. 사실 후자는 객체지향적 관점에서 그리 좋은 선택은 아니다. Vamsi Emani라는 프로그래머가 stack overflow에 남긴 질문 Why are static variables considered evil? 과 가장 많은 지지를 받은 두개의 답변을 번역했다.


Q by V. Emani

I am a Java programmer who is new to the corporate world. Recently I’ve developed an application using Groovy and Java. All through the code I’ve used quite a good number of statics. I was asked by the senior technical lot to cut down on the number of statics used. I’ve googled about the same, and I find that many programmers are fairly against using static variables.

저는 현업에 갓 뛰어든 자바 프로그래머입니다. 근래에 Groovy와 Java를 이용하는 어플리케이션을 개발하고 있습니다. 그동안 자바로 개발할 때 “static” 변수(그리고 static 메소드)를 꽤나 많이 이용하는 습관을 가지고 있었습니다. 근데 제 시니어는 static 의 개수를 줄이라고 말합니다. 그 이유가 궁금해서 구글에 검색을 해봤는데 많은 자바 프로그래머가 static 을 사용하는 것을 꺼린다는 것을 발견했습니다.

I find static variables more convenient to use. And I presume that they are efficient too (please correct me if I am wrong), because if I had to make 10,000 calls to a function within a class, I would be glad to make the method static and use a straightforward class.methodCall() on it instead of cluttering the memory with 10,000 instances of the class, right?

사실 저는 static 을 이용하는 것이 보다 편하고 효율적이라고 생각합니다. (제가 틀린 부분이 있으면 지적해주세요!) 어떤 클래스 내에서 만번의 함수 호출을 하게 된다면 그 함수를 static으로 만들어서 class.methodCall()의 형태로 사용하는 것이 만개의 인스턴스를 생성해서 메모리를 어지럽히는 것보다 훨씬 낫지 않을까요?

Moreover statics reduce the inter-dependencies on the other parts of the code. They can act as perfect state holders. Adding to this I find that statics are widely implemented in some languages like Smalltalk and Scala. So why is this oppression for statics prevalent among programmers (especially in the world of Java)?

PS: please do correct me if my assumptions about statics are wrong.

게다가 static 변수는 코드의 상호의존성(inter-dependency)을 줄여준다고 생각합니다. 상태를 저장하는데 있어서 static 변수들은 아주 유용하게 사용될 수 있습니다. 사실 static은 자바 뿐만 아니라 Smalltalk나 Scala 와 같은 프로그래밍 언어에서도 널리 이용되고 있습니다. 근데 왜 유독 자바 프로그래밍 세계에선 개발자들이 static의 사용을 꺼리는 걸까요?

PS: static 변수에 대한 제 생각에 틀린 부분을 지적해주시면 감사하겠습니다.


A by J. Skeet

Static variables represent global state. That’s hard to reason about and hard to test: if I create a new instance of an object, I can reason about its new state within tests. If I use code which is using static variables, it could be in any state – and anything could be modifying it.

Static 변수는 global state(역주: 전역 상태. 프로그램 혹은 한 모듈 전체의 상태)를 상징합니다. Global state는 추론과 테스트가 매우 까다롭습니다. 가령 코드에서 static 변수를 사용한다고 하면, 이 변수의 상태는 코드 여러 부분에서 영향을 받을 수 있게 되고 따라서 변화를 추적하기가 어려워집니다. 반면에 이를 객체화하여 인스턴스로 생성하면 테스트 중에 그 변수가 어떤 상태를 가지고 있는지 추론하는 것이 보다 간단해집니다.

I could go on for quite a while, but the bigger concept to think about is that the tighter the scope of something, the easier it is to reason about. We’re good at thinking about small things, but it’s hard to reason about the state of a million line system if there’s no modularity. This applies to all sorts of things, by the way – not just static variables.

프로그래머로서 제가 그동안 경험해온 바에 따르면 큰 개념에 대해서 그리기 위해선 일단 이해하고자 하는 범위를 좁혀 쉽게 추론할 수 있어야 합니다. 일반적으로 우리는 작으면 작을수록 그 대상을 쉽게 이해합니다. 다시 말해, 모듈화를 제대로 하지 않는다면 백만 줄 짜리 시스템의 상태에 대해서 추론하는 것은 굉장히 어려운 일입니다. 이것은 단순히 static 변수 뿐만 아니라 모든 프로그래밍 이슈에 대해서 적용할 수 있는 중요한 사실입니다.


A by A. Lockwood & J. Brown

Its not very object oriented: One reason statics might be considered “evil” by some people is they are contrary the object-oriented paradigm. In particular, it violates the principle that data is encapsulated in objects (that can be extended, information hiding, etc). Statics, in the way you are describing using them, are essentially to use them as a global variable to avoid dealing with issues like scope. However, global variables is one of the defining characteristics of procedural or imperative programming paradigm, not a characteristic of “good” object oriented code. This is not to say the procedural paradigm is bad, but I get the impression your supervisor expects you to be writing “good object oriented code” and you’re really wanting to write “good procedural code”.

첫째로, static은 객체 지향적이지 않습니다: 개발자들이 static 변수를 ‘악’으로 규정하는 이유는 static 변수가 객체 지향의 패러다임과 상반되기 때문입니다. 특히나 static 변수는, 각 객체의 데이터들이 캡슐화되어야 한다는 객체지향 프로그래밍의 원칙(역주: 한 객체가 가지고 있는 데이터들은 외부에서 함부로 접근하여 수정할 수 없도록 해야 한다는 원칙)에 위반됩니다. 질문자께서 스스로 설명했듯이 static은 스코프(역주: 한 변수가 유효한 범위)를 고려할 필요가 없는 경우, 즉 전역 변수를 사용할 때에 유용합니다. 이는 절차지향적 프로그래밍 혹은 명령형 프로그래밍(역주: C가 대표적인 절차지향적, 명령형 프로그래밍 언어이며 Java 역시 큰 범위에서 절차지향적, 명령형 프로그래밍 언어라고 할 수 있다.)에서 매우 중요한 개념입니다. 하지만 이 것이 객체지향의 관점에서 좋은 코드라고 얘기하기는 힘듭니다. 절차지향 패러다임이 나쁘다는 것이 아닙니다. 다만, 당신의 시니어는 당신이 “객체지향적으로 좋은 코드”를 짜기를 바라는 것입니다. 반대로 당신은 “절차지향적으로 좋은 코드”를 짜기를 원하는 것이라고 말할 수 있을 것입니다.

There are many gotchyas in Java when you start using statics that are not always immediately obvious. For example, if you have two copies of your program running in the same VM, will they shre the static variable’s value and mess with the state of each other? Or what happens when you extend the class, can you override the static member? Is your VM running out of memory because you have insane numbers of statics and that memory cannot be reclaimed for other needed instance objects?

사실 자바에서 static을 사용하기 시작하면 예측이 어려운 문제가 많아지게 됩니다. 예를 들어서 하나의 가상머신에서 어떤 프로그램 두 카피가 돌고 있다고 가정해봅시다. 만약 이 두 카피가 동일한 static 변수를 공유하게 된다면, 서로의 상태에 영향을 주게 되지 않을까요? 더불어서 오버라이딩을 할 수 없는 static 멤버들 때문에 클래스를 확장하는게 어려워질 것입니다. 뿐만 아니라 지나치게 많은 static 변수를 사용하게 되면 이들로부터 메모리 회수를 할 수 없어서 가상머신이 메모리 부족을 겪게 될 것입니다.

Object Lifetime: Additionally, statics have a lifetime that matches the entire runtime of the program. This means, even once you’re done using your class, the memory from all those static variables cannot be garbage collected. If, for example, instead, you made your variables non-static, and in your main() function you made a single instance of your class, and then asked your class to execute a particular function 10,000 times, once those 10,000 calls were done, and you delete your references to the single instance, all your static variables could be garbage collected and reused.

객체의 라이프타임: 추가로, static 변수는 프로그램이 실행되고 있는 내내 살아있게 됩니다. 즉, 그 클래스를 이용한 작업을 끝내더라도 static 변수가 점유하고 있는 메모리는 garbage collector(역주: 사용하지 않는 메모리를 회수하는 기능)에 의해서 회수되지 않게 됩니다. 반대로, 프로그래머가 그 변수를 인스턴스화 해서 main() 함수 내에서 하나의 인스턴스로 생성하게 되면, 그리고 그 인스턴스에게 만번의 함수 호출을 시키게 되면 그 만번의 함수 호출이 끝난 후 인스턴스는 소멸됩니다. 따라서 메모리를 훨씬 절약할 수 있게 됩니다.

Prevents certain re-use: Also, static methods cannot be used to implement an interface, so static methods can prevent certain object oriented features from being usable.

static은 재사용성이 떨어집니다: 또한, static 메서드는 interface를 구현하는데 사용될 수 없습니다. 즉 static 메서드는 프로그래머가 (재사용성을 높여주는)이러한 자바의 유용한 객체지향적 기능들을 사용하는 것을 방해합니다.

Other Options: If efficiency is your primary concern, there might be other better ways to solve the speed problem than considering only the advantage of invocation being usually faster than creation. Consider whether the transient or volatile modifiers are needed anywhere. To preserve the ability to be inlined, a method could be marked as final instead of static. Method parameters and other variables can be marked final to permit certain compiler optimizations based on assumptions about what can change those variables. An instance object could be reused multiple times rather than creating a new instance each time. There may be complier optimization switches that should be turned on for the app in general. Perhaps, the design should be set up so that the 10,000 runs can be multi-threaded and take advantage of multi-processor cores. If portability isn’t a concern, maybe a native method would get you better speed than your statics do.

static의 대안들: 프로그래머에게 효율(여기서는 속도)이 가장 중요한 문제여서 객체를 생성할 때 마다 생기는 사소한 불이익에도 민감한 상황일 수 있습니다. 이 경우에도 여전히 static 대신에 다른 방법들을 사용하는 것이 가능합니다. 먼저 “transient”나 “volatile”과 같은 제어자(modifier)를 쓸 수 있는지 먼저 고려해봅니다. 실행 속도를 빠르게 해주는 메소드 인라이닝(역주: 실제 메소드를 호출하지 않고 바로 결과값을 돌려주는 방식)을 위해 “final” 메서드를 사용하는 것도 생각해볼 수 있습니다. 또한 메서드 파라미터들과 변수들이 final로 선언되면 컴파일러 단에서의 최적화 작업이 가능해집니다. 인스턴스를 사용할 때마다 새로 생성하는 대신에 여러번 재사용할 수도 있습니다. 아마도 컴파일러 단의 최적화 작업이 switches that should be turned on for the app in general. 어쩌면 멀티스레드를 이용해서 멀티코어 프로세스의 장점을 극대화하기 위해선 이런 디자인이 필수적일 수도 있습니다. 이식성(역주: 다른 플랫폼으로 쉽게 옮길 수 있는 특성)이 중요한 것이 아니라면, native 메서드를 사용해서 static을 사용하는 것보다 더 빠르게 만들 수도 있을 것입니다.

If for some reason you do not want multiple copies of an object, the singleton design pattern, has advantages over static objects, such as thread-safety (presuming your singleton is coded well), permitting lazy-initialization, guaranteeing the object has been properly initialized when it is used, sub-classing, advantages in testing and refactoring your code, not to mention, if at some point you change your mind about only wanting one instance of an object it is MUCH easier to remove the code to prevent duplicate instances than it is to refactor all your static variable code to use instance variables. I’ve had to do that before, its not fun, and you end up having to edit a lot more classes, which increases your risk of introducing new bugs…so much better to set things up “right” the first time, even if it seems like it has its disadvantages. For me, the re-work required should you decide down the road you need multiple copies of something is probably one of most compelling reasons to use statics as infrequently as possible. And thus I would also disagree with your statement that statics reduce inter-dependencies, I think you will end up with code that is more coupled if you have lots of statics that can be directly accessed, rather than an object that “knows how to do something” on itself.

만약 여러개의 인스턴스를 만드는 것을 피하고 싶다면 싱글톤 디자인 패턴을 이용하는 것이 훌륭한 대안이 될 수 있습니다. 싱글톤 디자인은 (싱글톤을 제대로 구현했다는 전제하에) 스레드 안정성을 가지고, lazy-initialization(역주: 객체가 필요할 때마다 만들어 쓰는 기법)을 허용하며, 객체가 사용될 때마다 제대로 초기화 된다는 것을 보장합니다. 뿐만 아니라 서브 클래싱(sub-classing) 기법을 가능하게 하고, 테스트와 리팩토링이 매우 용이합니다. 다음의 상황을 가정해봅시다. 프로그래밍을 하다가 어느 시점에서 지금까지의 설계를 바꿔야겠다는 생각이 들게 되면 두말할 것도 없이 하나의 인스턴스를 수정하는 것이 모든 static 변수들을 리팩토링 하는 것보다 훨씬 편할 것입니다. 사실 static을 사용하다가 refactoring을 해야하는 상황은 매우 흔한 일입니다. 그것은 유쾌하지 않은 일일 뿐 아니라 훨씬 많은 클래스를 수정하게 만들기도 합니다. 이렇게 또다시 클래스들을 수정하다보면 새로운 버그를 만들어낼 소지가 매우 커집니다. 이런 상황을 피하기 위해서 처음에 “제대로”(위에서 언급한 방식들대로) 디자인하여 코딩하는 것이, 그 방식이 몇가지 단점을 가지고 있는 것 처럼 보여도 훨씬 나은 선택입니다. 사실 이런 끔찍한 재수정 작업이 요구될지도 모른다는 소지가 제가 static을 되도록 쓰지 않으려는 가장 큰 이유 중 하나입니다. 정리하자면, 저는 질문자께서 static이 코드의 상호의존성(inter-dependency)을 줄여준다고 말하신 것에 동의할 수 없습니다. 인스턴스화 되어 있는 객체들을 쓰지 않고 static 변수에 직접 접근하는 방식으로 코드를 짜다보면, 결국 작성한 모듈들이 서로 더 많이 엮이는 (바람직하지 않은) 상황에 처하게 될 것입니다.


가자고팀은 백엔드 어플리케이션을 Java로 개발하고 있다. Java로 개발을 하다보면 자주 쓰는 메서드들을 static (클래스 메서드)으로 선언하고자 하는 유혹이 생겨난다. 객체화를 할 필요도 없고 접근이 훨씬 용이하기 때문이다. 하지만 위의 두 개발자의 답변대로 static의 남용은 프로그램의 상태를 추정하기 어렵게 만들고 결과적으로 객체지향적이지 않은 코드를 작성하게 만든다.

물론 static을 ‘evil’이라고 규정하고 있는 이들의 의견에 전적으로 동의하는 것은 아니다. 그러나 필자도 개발 중에 static 을 빈번하게 사용하면 겪게 되는 문제들을 경험해본 적이 있다. ‘좋은 코드’라는 것에 결코 절대적인 기준이 있는 것은 아니지만, 객체지향적 프로그래밍의 원칙들을 되새겨볼때 분명 static의 사용에 심사숙고할 필요가 있어보인다.

By Eastsky Kang


출처 - http://tech.thegajago.com/2016/02/20/%EC%99%9C-%EC%9E%90%EB%B0%94%EC%97%90%EC%84%9C-static%EC%9D%98-%EC%82%AC%EC%9A%A9%EC%9D%84-%EC%A7%80%EC%96%91%ED%95%B4%EC%95%BC-%ED%95%98%EB%8A%94%EA%B0%80/

'Language > JAVA' 카테고리의 다른 글

Java 8 - Interface의 변화  (0) 2018.02.28
Generic 메서드  (0) 2017.10.20
자바 람다식(Lambda Expressions in Java)  (0) 2016.09.09
자바 JVM 정리(Java Virtual Machine)  (0) 2016.08.05
GC  (0) 2016.08.05
: