[.NET vs Java] goto

C를 배우거나, C/C++ 코딩을 하면서 초창기 질리게 들어봤을 발언 생각해보자.

goto 문 제발 쓰지 마라. 코드 망가지는 꼴 보기 싫으면.

이는 goto 및 대체 기능을 가진 그 어떤 언어를 배워도 마찬가지있다.
하지만, 해당 언어에 숙련되고 흐름을 충분히 숙지했다면, 흐름 제어는 피할 수 없는 숙명이다.
이제 그 숙명을 비교해보자.

JAVA

자바는 goto 문이 없다. 단지 예약어로만 되어 있을 뿐이다.
하지만, 자바는 label 기능을 흐름 제어의 한 역할로 가지고 있다.
몇가지 사용 방법이 있는데 알아보도록 하자.

// before common do something
myLabel:
{
    // do something
    if( someIsFalse ) break myLabel;
    // do other something
}
// after common do something

배울 일 없는 가장 기본적인 레이블 블록이다. 자바는 goto를 지원하지 않기 때문에,
의도치 않은 흐름 제어를 방지하기 위해 일반적인 레이블 블록의 continue 문을 막는다.
그래서 break 문과 레이블 문으로 흐름을 끊을 수 있는 방법을 제공한다.
일반적인 레이블 블록은 return으로 인한 나머지 식의 중단을 방지하기 위해 잠시 보너스 처리가 필요할 경우 사용한다.
물론 레이블 옆에 단일 블록으로 label: doSomething(); 처럼 할 수 있으나… 후술할 반복문 아니면 큰 의미 없으므로 여기선 패스.

// before common do something
myLabel: if(somethingis){
    // do something
    if( someIsFalse ) break myLabel;
    // do other something
}
// after common do something

그다음 배울 일 없는 조건절 레이블이다. 사용법은 위와 동일하다.

outterLoop: for(int i = 0; i < 10; i++)
{
    while(condition)
    {
        // some code

        if(someConditon) break outterLoop; // break the for-loop
        if(anotherConditon) break; // break the while-loop

        // another code
    }

    // more code
}

아마 자바의 레이블이라면 이 사용법을 배웠을 것이다. 보통 레이블을 가르칠 때 가장 안전하고, 흐름 제어라는 의미가 가장 부합되는 케이스가 이런 반복문이기 때문이다.
중첩 반복문에서, 레이블 없이는 상위 반복문을 제어할 방법이 없다. 왜냐면 break이나 continue 는 소속된 반복문만 제어가 가능하기 때문이다.
그래서 레이블을 통해 레이블 반복문을 정의 후, 그 안에 반복문이나 필요한 처리를 통해 흐름 제어를 수행한다.

자바의 레이블은 이렇듯 흐름 제어를 개발 실수를 줄일 수 있도록 상당히 엄격하게 정의했다. 자바스크립트도 마찬가지.

C

C#은 C++에 자바의 객체지향을 통합한 혼종 언어라도 해도 무방하다. 그래서 그런지 goto 문이 존재하고, 사용이 가능하다.
C#의 흐름 제어 꽃은 의외로 switch 문에서 빛나는데, 이는 후술하도록 하겠다.
C#의 레이블은 자바와는 다르게 분기로 존재한다.

forever: {
  // ...
  if(condition) goto never;
  goto forever;
}
never:;
//...

일단 자바와 같이 레이블은 블록 단위로 정의할 수 있다. 물론 상기 자바처럼 단일 블록 또한 가능하다.
하지만, break 으로 흐름을 중단시킬 수 있는 자바와 다르게 goto문을 통해 다시 레이블로 돌아갈 수 있다.
즉, 조건 없는 goto 문은 while(true) 와 다름없는 무시무시한 코드가 된다.
기억으로는 컴파일 시 warning 뜨긴 하지만… 여하튼 코드의 흐름을 정확히 이해하지 못했으면. 그냥 그렇구나 하고 넘어가기 바란다.

for(int i = 0; i < 10; i++)
{
    while(condition)
    {
        // some code

        if(someConditon) goto breaker; // break the for-loop
        if(anotherConditon) break; // break the while-loop

        // another code
    }

    // more code
}
breaker:;

이 반복문은 자바에서 작성한 반복문과 같은 로직으로 한 것이다. 하지만 뭔가 다를 것이다. 그렇다. goto의 특성상 자바와는 다르게 for 에다가 레이블을 줄 수 없는 상황.
만약 아까 자바처럼 for문에다 레이블 걸고 goto 걸면, 다시 for 문을 실행한다는 의미가 된다. 반복문의 흐름이 씹힌다는 것이다.
이를 조심해서 다루어야 할 것이다. 자바보단 유연하게 대응이 가능하긴 하지만, 흐름 제어 잘못하면… 작은 하마가 나타나서 너 좆되는거야.

switch (a)     
{
    case 3: 
        b = 7;
        goto case 4;    
    case 4: 
        c = 3;
        break;     
    default: 
        b = 2;
        c = 4;
        break;
}

switch 문이 C#에서 레이블의 존재에서 꽃이나 다름없다. 자바와 달리 C#에서는 case 문에서는 아래 case로 SKIP 못하고 반드시 break 문이 있어야 하는 대신, goto를 이용해 원하는 case로 이동이 가능하다.
이를 이용해 당연하겠지만 반복문도 만들 수 있다. 물론 잘못 쓰면 좆되는 건 매한가지. 어쩌면은 자바 입장에서는 부러운 부분인 것 같긴 하다.

자. 이제 자바와 C#의 레이블에 대해 비교해 보았다. 정의는 동일하지만, 사용하는 방법은 확연히 다르다는 것을 알 수 있다.
다시한번 강조하지만, 코드의 흐름이 확실히 보장되거나, 반복문의 흐름 제어가 필요할 경우에 레이블을 주로 사용하기 바란다.
만약 배운 지 얼마 안됐다면, 이 글은 그냥 재미로 흘러 넘어가기 바란다. 간단해 보여도 실무에서는 은근 크리티컬한 이슈이다.

composite / 2018년 6월 19일 / Piss Development / 0 Comments

Browser Fingerprinting ㅗㅜㅑ

HTML5 성행 이전에는 브라우저 내 사용자 식별 가능한 유일한 수단은 쿠키 뿐이었다.
그러다가 HTML5 표준화 이후, 다양한 스토리지 방식(Local Storage 등)을 통해 임의의 키를 사용자에 주입해 특정 사용자를 식별하는 행위가 가능했다.
하지만 이들 방식은, 브라우저 캐시만 날려도 날아가는 등 아주 손쉽게 사용자 흔적을 없애버릴 수 없고,
요즘 부라우저들은 호락호락하지 않아서 보안 이슈가 컸던 제3자쿠키에 대해 엄격해지기 시작했다.

HTML5 가 실험적 단계였을 2012년부터, 이를 보완하여 사용자 식별에 유용해 왠만한 사이트에서 성행하기 시작한 2가지 몇 가지 사용자 식별 방법이 생겨났다.

Canvas Fingerprinting

캔버스 지문채취. <canvas> 태그에 임의의 폰트 문자를 렌더링 시켜 거기서 나오는 hash 값을 통해 사용자를 식별하는 방법이다.
구현하는 게 생각보다 쉽고, 무엇보다도 “시크릿 모드”에서도 같은 식별 코드가 렌더링 되어 광고 뿐 만 아니라 여러 기업에서 지금도 질리게 써먹는 기술이다.
심지어 KT는 공유기 사용자를 식별하기 위해 이 방법을 쓴다고 한다… 와우. 징한 놈들…

이 기술은 2012년 5월 샌디애고 캘리포니아 대학의 한 교수가 발견한 기술이다. Pixel Perfect: Fingerprinting Canvas in HTML5
이게 2년 뒤에 엄청난 화제를 불러 일으켰다.The Web never forgets: Persistent tracking mechanisms in the wild
생각보다 꽤 오래 전에 발견한 기술이었고, 한국 또한 화제거리로 떠오를 때 한 개발자 블로그에서 발췌했다. Canvas fingerprinting – 쿠키 없이 사용자 추적
이 방식은 꽤 높은 유일 해시가 나와 화제를 불러일으키기도 했다. 100%까지는 아니지만 무려 95%라는 엄청난 유일성을 지니고 있다.
더 무서운 점은 소셜공유 위젯 사이트 addthis.com이 화제 일으키기 전에 몰래 사용해왔다는 것이다.

또한가지, 같은 렌더링을 구현해도 같은 값이 나와서 쿠키가 굳이 필요가 없을 정도. (에이전트, IP와 같이 서버로 보내면 땡이니까.)

당연히 개인정보 문제가 발생 안할래야 안할 수 없었고, 결국 이를 방지하는 브라우저 플러그인이나, Firefox에서는 자체적으로 막을 수 있는 옵션을 제공하기까지 했다.
막는 원리 또한 간단하다. Canvas API 호출 시마다 임의의 노이즈를 생성시켜 해시 값이 다르게 나오게 하는 간단한 원리다. 요즘은 왠만한 애드블록 확장에서도 지원하기도 한다.

AudioContext Fingerprinting

예전에 내가 잠시 작곡놀이를 재미지게 했던 때가 생각났다. 그 와중에 브라우저에서 HTML5 기본 오디오 API는 나를 흥분의 도가니로 넣게 했다.
바로 순수 웹으로 드럼머신이나 신디사이저를 만들 수 있다는 것. 하지만 데스크탑 한정이고, 완벽하지도 않다.
그러나… 역시 브라우저에서 창조 가능하면 죄다 지문 채취가 가능한 것인가…

AudioContext Fingerprint Test Page

이 페이지는 캔버스 지문 방식으로 화제가 된 1년 뒤에 나온 페이지다. 최초 발견 또한 비슷한 시기이지만 크게 화제가 되지는 못했다.
왜냐면 발견 당시에도 그렇고 지금도 이걸 쓸 만한 매리트가 없기 때문이다. 캔버스보다 느리고, 데스크탑만 몇몇 브라우저에서 지원한다.
원리는 캔버스 방식과 비슷하다. 파장을 생성하고, 압축(Compress)한다. 파장만 생성하면 일정하기 때문에 압축하는 과정도 거친다. 거기서 유일한 파장이 나온다고 한다.
재밌게도 폰트 채취는 덤. IE를 위해 플래시가 활성화된 경우 플래시를 이용하는 위엄까지 보여준다.

All in one: FingerprintJS2

이젠 살다살다 저걸 화제로 불러일으킨 팀이 이걸 오픈소스로 공개하고 팔 생각까지도 했다.
파는 것까진 아니지만 이 기술은 중국에서 존나게 좋아하고 존나게 즐겨쓴다고 한다…

Valve/fingerprintjs2

이 라이브러리에서는 아래와 같은 식별자 정보를 제공한다.

  • 에이전트 (브라우저 및 OS 등)
  • 언어
  • 색상 깊이
  • 해상도
  • 시간대(Timezone)
  • 세션 스토리지 여부
  • 로컬 스토리지 여부
  • 인덱스DB 여부
  • AddBehavior 탑재된 IE 여부
  • open DB 여부
  • 플랫폼
  • DoNotTrack 활성화 여부
  • 설치된 글꼴 (플래시,JS,CSS 사용)
  • 캔버스 지문
  • WebGL 지문
  • 플러그인 (IE 포함)
  • Adblock 설치 여부
  • 언어 변조 여부 (예를 들어 한국어 플랫폼에 일본어 사용)
  • 해상도 변조 여부 (음?)
  • OS 변조 여부 (예: 에이전트 바꾸는 플러그인 등)
  • 브라우저 변조 여부 (위와 동일)
  • 터치 스크린 감지 및 지원
  • 픽셀 감도 (화면 비율, 예: 16:9)
  • 에이전트를 통한 논리 프로세서 개수 추측
  • 장치 메모리 (이건 시발 W3C에서 공식 지원)

그리고 이 개새끼들은 아래 기능도 지원할 예정이라 한다.

  • 멀티 모니터 감지
  • HashTable 지원 여부
  • WebRTC 지문
  • 수학 상수
  • 접근성 지문(…)
  • 카메라 정보
  • DRM 지원 여부
  • 가속도 지원 여부
  • 가상 키보드
  • 제스쳐 지원(터치 스크린 한정)
  • 픽셀 밀도 (레티나나 고밀도 디스플레이 감지)
  • 비디오 및 오디오 코덱 지원
  • 오디오 지문

아 시발 그냥 나도 쓰는게 낫겠다 어자피 불법도 아니고 사용자 식별은 하긴 해야 하니 시발…
끗… 근데 나 지금 백엔드 프로젝트 투입중이라 업무상 만질 일은 일단 없다.

composite / 2018년 6월 8일 / Piss Development / 0 Comments

ROW_NUMBER() OVER (정렬 하기 싫다.)

먼저, 이 글은 오라클 뿐 만 아니라 다른 관계형 데이터베이스에도 적용 가능한 팁임을 명시한다.

오라클에는 ROWNUM이라는 가상 칼럼이 있다.
결과가 나왔을 때, 해당 행의 번호를 새기는 재미있는 칼럼이다.
하지만 주의해야 할 것은 ORDER BY에 영향을 받지 않는다는 것이다.
그런 즉슨, 지정된 테이블 내의 가상 행 순서를 반환한다는 특징을 가지고 있다.
예를 들면, 철수와 영희를 순서대로 기록한 임의의 테이블에 ROWNUM을 붙이고, 거기에 ORDER BY 붙여보자.

SELECT ROWNUM, NAME
  FROM NAMES
 ORDER BY NAME;

이렇게 호출하면, 뻔하겠지만 정렬 규칙에 의해 “영희”가 먼저 행에서 나오기 때문에, 아래와 같이 나오게 된다.

RWONUM NAME
2 영희
1 철수

만약 ORDER BY에 영향가는 행 번호를 원한다면 ROWNUM 말고 ROW_NUMBER() 윈도우 함수를 써야 한다.

SELECT ROW_NUMBER() OVER (ORDER BY NAME) ROUNUMBER, NAME
  FROM NAMES
 ORDER BY NAME;

이렇게 호출하면, 정렬에 따른 행 번호를 매기게 되고, 그 결과 또한 원하는 대로 나올 것이다.

RWONUM NAME
1 영희
2 철수

여기까지가 오라클의 행번호 칼럼이다. 알다시피 다른SQL에는 ROWNUM에 준하는 기능이 없다.
그래서 등록한 순으로 행 번호를 매길 때는 어떻게 해야 하나 고민할 때가 생길 것이다.
오늘 그걸 소개하기 위해 이 글을 싸지른다.

대상: 완전 구버전이 아닌 왠만한 관계형 데이터베이스
요약: ROW_NUMBER() OVER (ORDER BY [LITERAL BUT NOT NUMBER])

ORACLE

ROWNUM이 있는데 굳이 왜냐고 물어보는 당신에게 굳이 이 팁을 바치도록 하겠다.

SELECT ROW_NUMBER() OVER (ORDER BY NULL) RN, * FROM SOME_TABLE

MSSQL

MSSQL의 경우 리터럴 표현이 조금 빡세지만 리터럴만 표현 가능하다면 충분히 가능하다.

SELECT ROW_NUMBER() OVER (ORDER BY (SELECT NULL)) RN, * FROM SOME_TABLE

MySQL

MySQL의 윈도우 함수 기능은 8.0 부터 등장했다. 당연히 대부분 시스템은 5.x일 터… 에휴…

SELECT 
    @i:[email protected]+1 AS rownum, 
    t.*
FROM 
    SOME_TABLE AS t,
    (SELECT @i:=0) AS foo

그럼 8.0 미만 환경에서 rownum 정렬은? 안타깝게도 서브쿼리 써야 한다…
MySQL 8.0 이상은 MSSQL과 동일하다.

PostgreSQL

허전할 정도로 심플하긴 하다.

SELECT ROW_NUMBER() OVER () RN, * FROM SOME_TABLE

DB2

PostgreSQL 방식과 동일하다.

SELECT ROW_NUMBER() OVER () RN, * FROM SOME_TABLE

왜 이 팁을 날리는가?

Cartesian Product 이라고 들어봤는가?
우리말로 카테시안 곱이라던가, 데카르트 이름을 딴 데카르트 곱 등으로 불린다. 근데 왜 아무도 곱집합이라고 안하는지는 모르겠다.
집합 이론에 기본적으로 있는 놈인데 말이다. 하긴 중딩도 고딩도 합집합 교집합 여집합 등을 배우지 곱집합은 안배웠으니 몇몇은 모를 수도 있겠다.
하지만 확률 이론의 경우의 수 이론을 배웠다면 사실 둘이 쌤쌤이다.

어쨌든, SQL에서는 곱집합에 의해서 조건 없는 JOIN 이나 CROSS JOIN 을 명시하는 등의 행위 질의를 던지면, 테이블의 각 행들에게 빠짐없이 하나씩 모두에게 동등하게 부여해 행 개수가 늘어나는 기현상을 일으킨다.
당연한 거지만, 예를 들어 5개의 행 A와 8개의 행 B를 조건 없이 조인하면, 5×8 총 40개의 행을 생성시켜 버린다.

하지만 나에게는 그냥 각 행마다 순서대로 1:1 조인을 하고 싶었다. 오라클에서.
그래서 선택한 게 ROWNUM 가상 칼럼을 조인하는 방식이었다.

WITH A AS (
  SELECT 1 A FROM DUAL UNION ALL
  SELECT 2 A FROM DUAL UNION ALL
  SELECT 3 A FROM DUAL UNION ALL
  SELECT 4 A FROM DUAL UNION ALL
  SELECT 5 A FROM DUAL),
B AS (
  SELECT 'A' B FROM DUAL UNION ALL
  SELECT 'B' B FROM DUAL UNION ALL
  SELECT 'C' B FROM DUAL UNION ALL
  SELECT 'D' B FROM DUAL UNION ALL
  SELECT 'E' B FROM DUAL)
SELECT * FROM (SELECT ROWNUM RN, A FROM A) A, (SELECT ROWNUM RN, B FROM B) B WHERE A.RN = B.RN;

실행 결과는 여기서 보면 된다.

그렇다. 이게 바로 글을 싸지른 원인이었던 것이다.
끗.

composite / 2018년 6월 7일 / Piss Development / 0 Comments

자바에서 String 다룰 때 오해와 진실

어자피 다들 먹고사는데 자바 안다뤄본 사람 있나? 어? 자바 안해봤어? 넌 그럼 축복받은 거야. 축하한다.
어쨌든, 자바에서 String 을 다룰 때 여러 조언들이 있다. 초보부터 중고급까지 짚어야 할 것들을 추려서 간단하게 소개하겠다.
나중에 문자열을 잘 다뤄서 자바 앱 성능 잘 나온다고 고마워하고 싶으면 언제든 해라.

이 글은 자바 1.8을 기준으로 작성하였다. 9 이상에서는 아래 내용에서 꽤 달라질 수 있으니 주의를 요한다.
라고 하기엔 당장에 StringConcatFactory 클래스가 뭔지 소개하는 한글 문서조차도 없어 시발놈들…

자바에서 + 연산을 통한 문자열 합치기를 지양하라!

반은 맞고 반은 틀리다.
내가 전에도 관련해서 블로그 포스트에 올렸었다. 자바는 + 연산을 사용하면 String.concat 메소드를 쓰는 게 아니라,
컴파일 전 내부적으로 StringBuilder 클래스를 만든 후 다시 문자열로 돌려준다.
전 포스트에선 StringBuffer로 기재했는데, StringBuilder맞다고 한다.
참고로 닷넷은 + 연산 시 연산자 오버로딩 본문에 내부적으로 String.Concat 메소드를 사용하여 합치도록 구현되어 있다.

String a = "hello" + "world";
// 는 아래와 같다.
String b = new StringBuilder("hello").append("world").toString();

이런 특성 때문에 문자열을 합치는 일이 많을 경우 단순히 + 연산을 쓰면 성능이 떨어질 수밖에 없고, 메모리 비효율은 덤이다.

String a = "";

for(int i = 0; i < 10000; i++) {
    a = a + i;
}

// 이런 짓거리 하면 이렇게 구현하는 것과 같다.

String b = "";

for(int i = 0; i < 10000; i++) {
    b = new StringBuilder(b).append(i).toString();
}

이런 경우에는 주저없이 처음부터 StringBuilder 클래스를 사용하여 문자열을 합치는 게 더 좋다.


final StringBuilder a = new StringBuilder(); for(int i = 0; i < 10000; i++) { a.append(i); } final String b = a.toString();

위와 같이 코딩하면 특히 비동기에 대응하기 수월하다는 장점도 가질 수 있다.

그렇다면, 다음과 같은 궁금증이 생길 것이다.
StringBuffer 또는 StringBuilderString.concat 중 어느게 더 좋을까다.
당연히 승자는 StringBufferStringBuilder 이다. 왜냐? String.concat 내용을 보면 바로 답이 나온다.

    public String concat(String var1) {
        int var2 = var1.length();
        if (var2 == 0) {
            return this;
        } else {
            int var3 = this.value.length;
            char[] var4 = Arrays.copyOf(this.value, var3 + var2);
            var1.getChars(var4, var3);
            return new String(var4, true);
        }
    }

여기서 핵심이 새 배열에 복사하는 행위인데, 이거나 + 나 겉보기엔 원리에 별 차이가 없다.
단지, + 연산은 내부적으로 위에서 언급했던 과정을 거치기 때문에 조금 더 느리고,
이 메소드는 호출할 때마다 원체(문자)의 매번 배열을 재구성 하는 과정을 거치기 때문에 당연히 느릴 수밖에 없다.
StringBuilderStringBuffer는 처음부터 배열 크기를 일정하게 잡고 시작하기 때문에 합치는 과정이 concat 보다 월등히 빠르다.

참고: String concatenation with Java 8

다시한번 강조하지만, 단순히 문자열을 합친다면 그냥 + 연산이 효율적이고, 반복문 등 합치는 일이 잦을 경우 StringBuilderStringBuffer를 써라. 꼭이다.

자바에서는 문자열을 효율적으로 합치는 클래스가 StringBuffer 뿐이다?

어디 학원에서 배우셨어요?

Difference Between String , StringBuilder And StringBuffer Classes With Example : Java
오라클 직원이었던 글을 참고하여 설명 들어가겠다.
사실 둘의 차이는 하나 말고는 없다.
바로 쓰레드에서 안전하냐 아니냐 이 차이 뿐이다.

  • StringBuffer 클래스는 쓰레드에서 안전하다.
  • StringBuilder 클래스는 쓰레드에서 안전하지 않다.

기본 성능은 당연히 쓰레드 안전성을 버린 StringBuilder 클래스가 우월하다. + 연산 시 StringBuilder 쓰는 이유가 있다.

만약 평소처럼 쓸 때, 특히 비동기에 사용할 일이 없으면, + 연산이나 StringBuilder를 써라.
하지만 통신이나, 다른 쓰레드와 공유하거나, 비동기 작업이 필요하다면 StringBuffer가 효율적이라고 보면 된다.

뭐… 이것도 적재적소에 쓰는 게 맞다고 보면 된다. 예제는 어자피 위에서 클래스 바꾸면 다를 게 하나도 없으므로 안 쓰겠다.

위 둘의 성격을 잘 설명한 글이 있으니 참고하라.
Java에서 String, StringBuilder, StringBuffer의 차이

혹시 StringBuilder가 닷넷스럽다고 쓰지 말라는 미친새끼 있으면 나한테 불러와라. 뚝배기 깨버려줄테니.

자바에서 문자열을 비교할 때 반드시 .equals() 메소드를 써야 한다!

어느정도 맞다.

내가 왜 애매하게 반드시 그렇게 해야 한다도 아니고 어느정도 맞다고 했는가?
아마 자배 배울 때 아래와 같이 배웠을 것이다.

  • 자바의 == 연산자는 레퍼런스 비교이다.
  • 문자열은 클래스이기 때문에 레퍼런스가 서로 달라 문자열을 아무리 비교해도 반드시 false가 나온다.
  • 따라서 문자열 비교할 때는 반드시 .equals() 메소드를 써서 비교해야 한다.

일단은 맞다. 내가 이거 부정한 적은 없다. 하지만 2번째 가르침은 잘못 가르친 거다. 왜냐?
당연하겠지만 정말 개념찬 자바 강의가 아니면, 대학교조차 String.intern() 메소드를 그냥 지나가는 경우가 많다.
하지만 자바나 닷넷은 문자열을 관리할 때, 반드시 거쳐가야 한다. 안그러면 자바 최적화에서 놓치기 쉽기 때문이다.

문자열 Pool이라 들어봤을 것이다. 보통 우리는 문자열을 정의할 때, "a" 처럼 쌍따옴표를 쓰지 new String 쓰지 않는다.
그렇다고 new String("a") 이렇게 선언한다고? 세상에 미친 짓도 이런 미친 짓은 없을 것이다. 메모리 2번 먹는다 생각하면 된다.
어쨌든, 쌍따옴표로 문자열을 정의하면, 아래와 같이 해석된다.

String a = "hello";
// 위 구문은 아래 구문으로 해석한다.
String b = new String(new char[]{'h', 'e', 'l', 'l', 'o'}).intern();

intern 메소드의 쓰임새는 그다지 어렵지 않은데, 문자열을 메모리에 담는다. 그리고 서로 다른 문자열끼리 메모리에 담게 된다.
따라서 아래와 같이 정의하면 새로이 문자열이 추가되는 일은 없다.

String a = "hello"; // 새로운 hello 문자열을 저장소에 담는다.
String b = "hello"; // 이미 담았으므로 다시 불러와 정의된다.

즉, 자바로 치자면 중복없는 컬렉션을 담당하는 Set 기반 클래스에 String.equals() 메소드로 비교하여 담는다고 생각하면 쉬울 것이다.
그렇기 때문에, 자바의 문자열 비교는 의외로 놀라운 결과를 보여주기도 한다.

String a = "a";
String b = "a";
String c = "b";
String d = new String(new char[]{'b'});

System.out.println(a == a); // true
System.out.println(a == b); // true
System.out.println(b == c); // false
System.out.println("b" == c); // true
System.out.println(c == d); // false

변수 ab의 경우, a 변수에 선언할 때, 풀에 문자열을 담게 되고, b 변수에 선언할 땐 풀에 있으므로 다시 불러오게 된다.
그렇기 때문에 String 클래스의 레퍼런스조차 같다. 그렇기 때문에 a == b 의 결과는 true가 되는 것이다.
하지만 "a""b" 는 딱 봐도 다른 문자열이기 때문에 레퍼런스도 틀리다. 당연히 결과는 false가 된다.
하지만 d 변수는 아예 클래스로 선언했다. 풀에 담지 않았기 때문에 문자열이 같아도 레퍼런스는 틀리다. 그래서 c == d의 결과는 false가 된다.

여기까지 하면 굳이 equals 안써도 된다고 생각하기 쉬운데… 안타깝게도 자바는 자비로운 놈이 아니다.
그 이유인 즉슨, 바로 String 클래스의 멤버부터 StringBuilderStringBuffer, Stream 계열의 문자열 버퍼 스트림 클래스 등이 문제가 되는데,
이들은 반환 값이 모두 new String 이렇게 문자열 클래스로 선언하여 보내준다. 왠만한 클래스 내의 toString 메소드 오버라이딩도 마찬가지다.
굳이 이유를 알려주자면, 문자 임을 잊지 말자. String 클래스 소스 까보면 알겠지만, 문자열을 다룰 때 문자열 자체를 다루는 게 아니라 내부적인 char[]에 담아 처리하게 된다.
당연하겠지만 결국 번거롭게 작업하는 대신 성능을 높이려는 신의 한수라고 생각하면 된다. 이건 버퍼나 스트림 처리할 때도 마찬가지이다.
그래서 같은 문자열 내용이라도, 레퍼런스 비교는 틀리다 보니 결국 이런 결과가 나온다.

System.out.println("abc".substring(0,1) == "a"); // false

만약 굳이 == 비교를 통해 비교하려면, .intern() 메소드를 써야 가능해진다.

System.out.println("abc".substring(0,1).intern() == "a"); // true

하지만 누가 번거롭게 일일이 intern 메소드를 쓰는가? 게다가 메모리 효율성에 전혀 좋지 않는 짓이다.
왜냐면 문자열을 intern 으로 호출하면, 그 문자열은 풀에 담게 되는데, 다들 불변성(Immutable)이라 들어봤을 것이다.
게다가 intern 메소드는 네이티브 메소드다. 네이티브에서 메모리를 직접 관리한다. 그래서 불멸성이 가능한 것이다.
대신, 이로 인해 개발자는 자바 내에서 저 문자열에 대한 메모리 관리는 영영 빠이빠이 되는 것이다.

문자열 관리의 3규칙, 명심하자. 다른 글에서도 질리도록 강조한다.

  • 따옴표로 감싼 정적 문자열은 적당히 쓰자. 너무 많으면 선언부터 사용까지 골치아픈 일이 발생한다.
  • 암호화나 해시처럼 문자를 세부적으로 다루지 않는 이상 new String 처럼의 클래스 초기화는 필요 없다.
  • 동적으로 생성된 문자열은 대부분 풀에 담지 않은 문자열 클래스이기 때문에, 값 비교엔 equals 메소드로 비교하라.

그래서 문자열을 비교할 때 결국 equals 메소드를 쓰라는 결과가 나오는 것이다.
내부적으로 String.equals 메소드가 값을 비교하도록 정의되어 있기에, 문자열 비교에 효율적일 수밖에 없을 것이다.

자, 물론 결론은 진실은 맞지만, 아는 사람들은 다 아는 뻔한 얘기지만, 이런 불편한 진실이 있다는 것을 상기시켜 주기 위해 추가했다.
참고로 닷넷 또한 자바의 문자열 관리와 비슷하다. 대신 == 비교 시 연산자 오버로딩에 의해 내부적으로 String.Equals 메소드로 비교하기 때문에 레퍼런스로 비교되는 일은 없다.

만약 더 있으면 추가하도록 하겠다.
끗.

composite / 2018년 5월 18일 / Piss Development / 0 Comments

IP 0.0.0.0 주소가 가지는 의미?

지금부터 내가 싸지르는 글은 서버 개발자를 위한 글이 아니다.
그냥 당신이 어느정도 컴퓨터 좀 다룰 줄 아는 모든 이들을 대상으로 쓰는 유용한 팁 글이다.
마음을 비우고 차분히 읽어보기 바란다.

일단 먼저 이론부터 보자면, IP 주소 0.0.0.0 은 유효한 주소다.
근데 이론만이다.

하지만 실제로 0.0.0.0 주소는 당연하겠지만 할당 가능한 IP 주소가 아니며, 논리적 용도로 사용한다.
위키페디아 0.0.0.0 문서를 보면 여러 의미로 사용되곤 한다.
문서 상에서는 메타 주소라 칭하고 있다. 그렇다. 우리식 대로는 물리적 주소가 아닌, 논리적 주소라 해석해도 손색이 없다.

하지만 한국에서는 0.0.0.0 얘기를 꺼내기 시작하면, TCP/IP 이론부터 들고 일어나 서버쪽 공부를 시키게 될 것이다.
당장에 구글 한국어 검색이나 네이버를 뒤지면 이런 얘기들 뿐이다.
서버에 관심 없거나 모르는 사람을 위해, 서버측 이론을 당장 한 마디로 함축하면,
0.0.0.0 주소는 “나는 어떤 IP 주소로 서비스할 지 모르니 아무 IP 대역 다 서비스 해 줘.” 라는 뜻이 되겠다.
여기서 다른 방향으로 넘어가면, 서버 프로그램이 0.0.0.0 주소를 어떻게 사용하느냐 나름이겠지만, 묵시적 규칙으로 대부분 이렇게 사용한다.

하지만 네트워크 클라이언트에서도 0.0.0.0 주소를 사용하기도 한다.
당장 OS 상관없이 가장 빠르고 쉽게 접할 수 있는 가장 대표적인 예로 HOSTS 파일이 있다.
자, 하지만 서버와는 달리 0.0.0.0 의 쓰임새도 없다. 할당할 IP가 없다. 그렇다면 뭐다? 없다.
그렇다. HOSTS 파일의 0.0.0.0 IP 주소는 “어느 IP 주소도 할당하지 마라.” 라는 뜻으로 보면 된다.
만약 우리가 HOSTS 파일에 0.0.0.0 naver.com 줄을 추가하여 저장 후 브라우저를 킨다면?
네이버 접속하자마자 바로 페이지를 찾을 수 없다고 뜰 것이다. 1초의 망설임도 없이 컴퓨터는 접속 오류를 내뱉을 것이다.
왜냐, 0.0.0.0 이 가지는 라우터도 없고, 물리적 할당 공간도 모르며, 어디로 접속해야 할 지 아예 정해지지 않았기 때문이다.
그래서 HOSTS 파일 작성 시, 원치 않는 도메인을 바인딩하려고 할때 (주로 광고나… 어둠의 유지용) 127.0.0.1 대신 사용하라는 것이다.
127.0.0.1 주소는 다들 아시다시피 로컬 IP 주소다. 만약 이 주소로 바인딩을 시도하면, 컴퓨터는 자신의 컴퓨터를 “가상 루프백 네트워크 드라이버”를 통해 접속하려 할 것이다.
그러다가 접속할 수 없으면 접속 오류가 뜬다. 그렇기 때문에 HOSTS 에서는 원치 않는 도메인을 127.0.0.1 대신 바로 접속을 중지해버리는 0.0.0.0 주소를 권장하는 것이다.

네트워크 클라이언트에서도 0.0.0.0 주소는 요긴한 기능으로 사용하기도 한다. 상기 위키페디어를 가면 알겠지만,
당신의 랜 카드에 IP를 할당해야 하는데, 모르겠다? 그냥 자동으로 받고 싶다? 그러면 우리가 보기에는 DHCP 사용에 체크하거나 설정할 것이다.
그러면 네트워크 연결 프로그램은 이걸 할당 IP 주소를 내부적으로 0.0.0.0 으로 설정한 다음, 접속 가능한 게이트웨이로부터 자동으로 IP를 받는 서버로 IP를 할당받으려 할 것이다.
그러지 못하면 169.254.xxx.xxx 라는 듣도보도 못한 IP 주소를 받고 네트워크 활동을 못하는 참사가 일어나겠지.
어쨌든, 네트워크 연결 프로그램에서는 0.0.0.0 주소의 의미는 “나는 어떤 IP 주소를 할당받을 지 모르겠으니 자동으로 받아 주시오.” 뜻이 되겠다.

지금까지 IP 얘기는 IPv4 기준이었고, IPv6 에서 같은 역할을 담당하는 주소는 콜론 2개 딸랑 :: 쓰면 된다. 참으로 간편하지 아니한가?

올바르지만 올바르지 않는 0.0.0.0 IP의 세계는 결국 앱이 정하는 기준에 따른다고 보면 된다. 전체적으로는 “몰라, 안써!” 의미가 되겠다. 하지만 이 의미가 유용하게 쓰이기도 한다는 점을 알아두기 바란다.
끗.

composite / 2018년 5월 8일 / Piss Development / 0 Comments

사설 네트워크를 위한 네트워크 서비스

1. Hamachi

말할것도 없다. 일단 가장 유명하고, 많은 사용자를 보유하고 있다.

  • 무료: 5명까지 연결 가능, 대역폭 제한.
  • 유료: 32 네트워크 지원 월 49$/월, 이상의 플랜 제공, 대역폭 제한 없음.
  • 지원 플랫폼: 윈도우, 리눅스, 맥

2. Tunngle

게이머에게 유명하다. 255명 이상의 네트워크를 지원하는 대신 공개 네트워크이며, 매 접속시 다른 IP를 할당받는다.
베이직 플러스 이상에서만 고정 IP를 할당받을 수 있다. 무료의 경우 광고도 있다.

  • 무료: 공개 내트워크 내 255명까지 지원
  • 유료: 베이직 플러스, 프리미엄과 평생 라이선스가 있으며, 각각 1.18$/월, 2.37$/월, 23.74$. 프리미엄 이상에서만 비공개 네트워크 구축 가능.
  • 지원 플랫폼: 윈도우
  • 게이밍에 특화된 네트워크 플랫폼으로 사설 네트워크에 적합하지 않음.

게임의 특화된 네트워크 서비스는 그냥 구글검색 해줘라. 아니면 꺼라위키 가던가.

3. NetOverNet

하마치와 비슷하긴 한데, 하마치하고 달리 내장 VPN도 지원하는 프로그램(PPTP, L2TP 등). 대신 무료 플랜이 3개 컴퓨터와 4mbps/s로 좀 짜긴 하다.

  • 무료: 비공개 네트워크 내 3명 지원, 대역폭 제한.
  • 유료: 베이직 5$/월 8개의 연결 지원, 어드밴스드 10$/월 16개의 연결 지원, 그 이상의 옵션 협의
  • 지원 플랫폼: VPN Client를 지원하는 모든 운영 체제 및 윈도우 프로그램 제공

4. FreeLAN

일단 성격은 VPN인데, 실장 가상LAN이다. contact 외부 주소가 없으면 내부 네트워크용이 되는거고, 정말 개인 네트워크스럽다.
그리고 GUI 프로그램이 없으며, 텍스트 방식의 설정 파일과 콘솔 프로그램이 전부이다.
하지만 무료, 무제한 개인 네트워크 구축은 상당히 매리트가 있다고 보면 된다. 네트워크도 생각보다 안정적이라고 한다.

  • 지원 플랫폼: 윈도우, 리눅스, 맥
  • 인터넷을 통한 LAN 접속 시 서버 쪽에서 방화벽 오픈해야 함.

5. LAN Bridger

제공된 정보가 없다. 대신 개인 네트워크 범위를 제공한다. 윈도우만 지원한다. 공식 사이트에서는 게이밍을 강조했으니 게이밍에 적합할 듯 하다.

6. NeoRouter

2가지 방식을 제공한다. 자체 서버 구축 방식과 Mesh라 해서 클라우드 구축 방식이다. 서버와 클라이언트 모두 프로그램이 별도로 필요하긴 하지만,
클라이언트의 경우 왠만한 데스크톱과 모바일 플랫폼 모두 지원한다. 방화벽이 뚫려있는 네트워크 환경이거나 회사 환경에서는 괜찮은 방법이다.

  • 지원 플랫폼: 윈도우, 리눅스, 맥, iOS 및 안드로이드, 라즈베리, FreeBSD, OpenWRT 지원 공유기 등
  • 무료: 255개 연결.
  • 유료: 연결 수 단위 패키지 판매 또는 클라이드 월정액 판매. 고급 사용자 관리 및 방화벽, 모니터링 및 추적 기능 제공.

7. ZeroTier

위 NeoRouter Mesh와 비슷한 버전이라 생각하면 된다. 중계 서버를 제공하는데, 공개형과 비공개형이 있다.
공개형 네트워크는 무제한 연결이 가능하며, 비공개형 네트워크는 100개의 연결을 지원한다.
전에도 언급했듯이 네트워크 연결 시 마이페이지에서 승인해야 하는 점은 여전하다. (단, 컴퓨터 당 한 번만 승인하면 된다.)

  • 무료: 무제한 공개 연결 및 100개 비공개 연결 (계정당)
  • 유료: 무제한 비공개 연결을 지원하는 베이직(29$/월) 및 자체구축을 지원하는 프로(100$/월)이 있음.
  • 지원 플랫폼: 윈도우, 맥, 리눅스, 몇몇 유명 NAS (GPL 오픈소스), iOS 및 안드로이드.

8. DynVPN

베타라서 언제 끊기나 했는데 아직도 멀쩡히 잘 살아있고, 공식 페이지에서도 가능한 영원히 무료로 제공하겠다고 공언했다. 일단 베타 딱지는 끊은 듯.
비공개 무제한 네트워크를 무료로 제공하는 특징이 있다. 방식도 여전히 컴퓨터를 미리 등록 후 나오는 비밀 키를 컴퓨터에 설치 시 등록하는 점이 되겠다.

  • 지원 플랫폼: 윈도우, 맥, 리눅스, 라즈베리파이

composite / 2018년 4월 30일 / Dog's bullshit / 0 Comments

즉석 관리자 권한을 위한 윈도우 BATCH 스크립트

간단한 팁을 주도록 하겠다.
아마 가장 짧은 관리자 권한 상승 후 실행 스크립트 되겠다.

배치 파일을 작성하다 보면 관리자 권한 상승을 요할 때도 있다.
그러다가 관리자 권한 여부를 확인 후 아니면 관리자 권한 달라고 메시지 날리고 끌 수도 있긴 하다.
하지만 사용자에겐 불편할 수밖에 없다.
그래서 Stack overflow에서도 배치 파일로 관리자 권한 상승에 대한 커뮤니티 연구가 진행되었고.
우린 윈도우 7 까지는 관리자 권한 상승을 아예 꺼서 못느꼈을 수도 있겠지만,
윈도우 8부터는 관리자 권한을 끄면 여간 불편한 일이 생기는 게 한두개가 아니고 레지 건드리는 방법 외엔 없어서
국내 액티브엑스도 처음엔 관리자 권한 끄라고 요청했다가 보안 전문가들에게 털리고 이제 관리자 권한 상승을 요구한다.

어쨌든, 이 마법의 구분을 공개하도록 하겠다.

@ECHO OFF

NET SESSION 2>nul >nul
IF %ERRORLEVEL% NEQ 0 (
IF "%1" == "ELEVATED" GOTO NOTELEVATED
GOTO ELEVATE
)
GOTO ADMINTASKS

:ELEVATE
pushd %~dp0
MSHTA "javascript: var shell = new ActiveXObject('shell.application'); shell.ShellExecute('%~nx0', 'ELEVATED', '', 'runas', 1);close();"
EXIT

:ADMINTASKS
REM 여기에 관리자 권한 상승 후 배치 내용 나열
PAUSE
EXIT

:NOTELEVATED
echo No admin rights
PAUSE
EXIT

자, 처음에 NET SESSION 이라는 꽤 생소한 명령어가 있다. 보통 NET 명령어는 서비스 시작/종료하거나 방화벽 설정 시 자주 사용한다.
SESSION 명령어는 당신 컴퓨터로 공유 폴더던 뭐던 접속할 때 컴퓨터 목록을 띄우는 명령어인데, 목록이 있던 없던 종료 코드는 0이고, 대체적으로 관리자 권한이 없는 경우 외에 오류 코드가 없기 때문에 사용한 것이다.
게다가 NET 명령어는 HELP 수식어가 없으면 무조건 관리자 권한이 필요한 특징을 가지고 있다. 그래서 가장 간단하게 관리자 권한 여부를 확인할 수 있는 마법의 명령어 되시겠다.
뒤에 2>nul >nul 은 아무것도 출력하지 못하게 하는 연산 명령어다. 보통 파일명 붙이면 명령어 출력 결과를 파일로 저장하는데, nul은 일종의 블랙홀 되시겠다.
2는 오류 출력을 가리키는데, 오류 출력도 가리고, 일반 출력도 가리게 하는 연산 명령어라 보면 된다.

이리하여 if 문으로 명령어 결과 코드가 0이면 관리자 권한으로 넘어가면 되고, 그 외 숫자일 경우 관리자 권한을 요청하여 분기로 나눈다.
이제 중요한 부분인데, 보통 BAT 자체로는 관리자 권한 상승이 불가능하기 때문에 임시 폴더 등에 Shell.Application 객체가 담긴 vbs 파일을 만들어 실행했었다.
하지만 이번에는 시스템급 웹 페이지를 띄우는 .hta 파일을 실행하는 mshta를 사용했다. javascript: 프로토콜도 먹힌다. 애초에 엔진이 IE니까.
그리고 내용이야 vbs 생성 내용과 크게 다를 거 없다. 단지 특징이 있다면 배치 파일 자신을 다시 실행하는 거다. 이것도 기존과 크게 다를 게 없다.
이리하여 관리자 권한을 얻으면 다시 BAT 파일을 실행하게 되고, 못얻으면 그냥 종료된다.
관리자 권한을 얻게 되면, ADMINTASKS 부분으로 이동하여 명령어를 실행하게 된다. 그 부분 아래 원하는 명령어 내용을 입력하면 된다.
말이 거창하지만 짧고 간결하며 윈도우 10 최신 환경에서도 실행 잘되는 배치 파일 되시겠다. 유용하게 쓰도록.

출처: Stack overflow – How can I auto-elevate my batch file, so that it requests from UAC administrator rights if required?

composite / 2018년 4월 27일 / Piss Development / 0 Comments

경력있는 신입 개발자 공채 안내 (부제: 그 회사는 믿고 걸러라)

요즘 스타트업부터 중소, 중견기업, 심지어 대기업까지 소위 경력있는 신입 개발자를 뽑고 있다.
경력있는 개발자의 예를 들자면,

경력있는 신입 개발자 예

여기서 경력있는 신입 개발자를 뽑는 특징을 분석하면 대충 이러하다.

  • 절대 경력을 뽑지 않는다. 대부분 선임 개발자가 있는 경우가 대부분이기 때문.
  • 선임 개발자와, 대표 또는 인사담당자 간의 충원 안건 협의 후, 어자피 지식은 없으니 형식적으로 기술.
  • 또는, 선임 개발자의 인사업무 경력 없는 의도적인 서술.
  • 가장 대표적인 예로 필요한 기술들을 아는대로 일단 나열하고 보는 식.
  • 심지어는 신입을 뽑는데 경력을 요구하는 경우. 예) 회계 업무 경험자
  • 그리고 마지막으로 지원자격과 우대사항을 거창하게 써놓고 그 다음 복리후생 같은 안내와 채용 과정을 대충 싸갈기거나 취업 사이트 기본 템플릿 그대로 기재.
  • 연봉낚시 (요즘 신입 연봉 4000 이상 심지어 5000 내외 준다는 낚시성 공채가 많다)

대부분 공채에 해당하며, 추천의 경우는 저런 거창한 내용이 없으므로 그냥 기존 개발자 주위에 적당한 인맥에 맞는 인재 구해다 쓰는 경우가 대부분이다.

이런 회사들에 들어갈 경우, 일단 서류와 면접은… 거창한 내용과 달리 별 다를 게 없다. 정말로.
하지만 헬게이트는 입사 확정하는 순간부터이다. 당연하겠지만…

  • 중소기업이나 스타트업 주제에 신입 연봉으로 4000 이상을 준다고? 천만에. 절대로 안준다. 무조건 핑계대면서 신입 연봉으로 맞춘다. 무조건이다. 100%다.
  • 의무는 정직원, 권리는 프리랜서(즉, 없다. 수습기간은 기본으로 깔고, 4대포험 외의 복리후생 따위는 없고, 휴가도 없다).
  • 무능력한 선임 개발자 또는 악랄한 선임 개발자, 또는 곧 나갈 개발자 셋 중 하나 이상을 만난다.
  • 인수인계 기간이 짧다. 10년 경력의 고급 개발자도 1달 미만의 인수인계 기간이 벅찬데, 신입에게 2주의 인수인계 기간을?
  • 개발자가 아닌 직원 및 대표는 아마 뽑힌 개발자가 맥가이버인줄 안다.
  • 유난히 성과를 중시하는데, 특히 개발자에게 성과는 의무다. 왜냐고? 개발자는 인력 투자가 아닌, 손실 비용으로 취급하기 때문…
  • 이들 회사는 해당 직원에 대한 유사시 대비를 위해 취업부터 퇴직까지 온갖 안전장치와, 정부지원 두마리 토끼를 잡아 먹고산다. (대부분 중소기업의 종특)

내가 감히 신입 개발자에게 취업 조언을 하자면, 물론 예전보다 좀 빡세진 감은 있긴 하다. 하지만 어쩔 수 없다. 기술이 발달했기 때문에.

  • 초봉 평균 3000 정도다. 물론 이상 주는 곳도 있다. 하지만 너무 많이 준다하면 아무리 네임드라도 위 사례처럼 사기성이 짙다. 가지 마라.
  • 코딩 시험 및 이론은 필수다. 반드시 익히고 그런 스킬을 요구하는 곳으로 들어가라. 요구하는 곳은 최소한 날로 먹는 개발 실무진들이 아니다.
  • 포폴은 하나씩 준비하라. TODO 같은 허접한 프로그램이라도 상관없다. 자신의 기술로 만들 수 있다는 거 하나씩 준비하라. 많은 도움이 될 것이다.
  • 인맥은 반드시 챙겨라. 이건 그 어느 직종이던 무조건 필수 사항이다. 인재추천으로 쉽게 들어갈 정도는 아니지만, 경험에서 우러나온 팁이 인터넷에 돌아다니는 팁보다 더욱 알차다.
  • 흔히 사용하는 언어로 하되(자바, 파이썬 등), 남이 잘 안하는 기술은 허접해도 상관없으니 익혀라. (예: 인공지능, 블록체인 등). 필요 시 당신의 구세주가 되줄 수 있다.
  • 자신의 주력기술을 파악하고 단련하라. 그 어떤 언어던, 기술이던 상관없다. 맞다 싶으면 미치도록 파라. 선배 및 선임에게 신임을 주기 아주 좋은 모습 바로 그 모습이다.
  • 확실한 취미를 가져라. 여러 사람이 가질 수록 더욱 좋다. 테니스나 탁구, 오타쿠가 되어도 상관없다. 단체 생활의 기본이다. 특히 취업 후 퇴근이 부드러워진다.
  • 만약 자신이 할 수 있으면 어느 곳이던 참여하라. 그게 경력이고 커리어다. 세미나나 기술발표 등, 회사에 양해를 구해서라도 참여하라. 인맥과 기술단련 두마리 토끼가 잡힌다.

끗.

composite / 2018년 4월 26일 / Piss Development / 0 Comments

개인적으로 Cygwin을 절대 비추하는 이유 (부제: 걍 WSL 써라)

지금은 윈도우 10에 서브시스템 우분투를 설치해 우분투 내에서 할거 하고 있다.

node.js 가 아직 윈도우를 지원하지 않던 시절, 나는 한번 cygwin 을 깔아서 node.js를 설치했다.
잘 된다. 일단은. 일부 기능이 빠졌다고 나와 있다고는 하지만 딱히 불만은 없었다.
하지만 cygwin을 쓰면서 네이티브 리눅스와보다 불편한 감을 지울 수 없었고,
게다가 MS가 직접 나서서 libuv를 윈도우 포팅에 성공하여 node.js가 윈도우에서도 쓸 수 있는 날이 왔고,
나는 이제 더 이상 cygwin이 필요 없어서 지우려고 했으나… 안됐다.
결국 나는 윈도우를 밀어서 cygwin의 흔적을 지워버렸다.

Cygwin은 UNIX 콘솔의 편리함을 그대로 윈도우에서 쓸 수 있는 일종의 미들웨어이다.
Cygwin에서 유닉스 기반의 네이티브 컴파일도 가능하고 왠만한 도구들(쉘, 프로그램, 도구, ssh, git 버전관리 등등)을 그대로 지원한다.
하지만, 나는 이걸 쓰는 것보다 차라리 윈도우 10을 깔고, 거기에 서브시스템 리눅스를 깔라고 하고 싶다.
위키에서도 소개되긴 했지만… 왜그런지 짧게 설명자면…

  • 패키지 관리자의 부재 (apt, yum 등)
  • Windows 계정 종속적인 사용자 (Bitvise SSH Server도 마찬가지긴 하지만…)
  • 일부 커널 종속적인 프로그램 미지원 (docker 등)
  • 편해 보이지만 은근 불편한 언인스톨 시스템
  • 더럽게 느린 성능
  • 애매한 보안 정책 (관리자 계정은 root…)

아무리 장점이 많아도 단점이 모두 씹어먹기 때문에 나는 앞으로도 cygwin을 이용할 생각 절대로 없다고 보면 된다.
만약 윈도우에서 리눅스를 돌리고자 한다면, 나는 단 1초의 고민도 없이 윈도우 10의 서브시스템 리눅스를 권유하거나, 가상OS를 권하고 싶다.
VMWARE나 VirtualBox 등 가상 사용법이야 뭐 다들 알 것 같으니 넘어가고, 윈도우 10의 리눅스 기능에 짧막하게 소개하겠다.
일단, 윈도우에서 설치 가능한 리눅스는 아래와 같으며,
심지어 윈도우 서버 2016에서 빌드 1706 이상일 경우에도 일부 리눅스 설치가 가능하다.

  • Ubuntu (서버 2016 지원)
  • openSUSE (서버 2016 지원, Hyper-V 공식지원)
  • SLES (SUSE Linux Enterprise Server) (서버 2016 지원, Hyper-V 공식지원)
  • Kali Linux

해킹과 보안에 매달리는 사용자는 Kali까지 지원되니 고민 없이 설치하면 된다.
비록 설치 시 손 댈 곳은 많지만, 완벽한 리눅스 환경을 제공하면서, 게다가 커널도 일반 리눅스 커널이라 지원되는 커널이 있는 프로그램이라면 모두 설치가 가능하다.
게다가 성능은 기존 자원을 유동적으로 활용하기 때문에 사양에 따르긴 하겠지만 Cygwin보다 훨씬 부드럽게 동작한다.
나는 Ubuntu를 설치했는데, 재밌는 점이 윈도우 상에서 관리자 권한을 필요한 폴더나 파일일 경우 Ubuntu 에서도 sudo 등의 권한 상승을 요구한다는 점이다.
물론 TrustedInstaller 권한이 있는 파일이나 폴더는 죽어도 못건드린다…

어쨌든 간에, 회사에서 리눅스 개발이나 테스트를 겸하고 싶다면, 2가지 방법이 있는데,
스냅샷 등의 크리티컬 테스트를 요하는 환경이라면 아무래도 가상환경이 가장 이득이며,
그게 아닌 왠만한 실행 테스트 환경을 원한다면 윈도우 10에 리눅스 환경을 설치하는 것이 좋다. 회사에서는 그게 더 싸다. 물론 아예 리눅스 까는것보단 비싸긴 하겠지만, 문서작업 때문에 윈도우 쓸 수밖에 없는데 뭐.

추가내용:
WSL에서는 docker 못돌린다. 커널과 환경은 docker 사양에 맞긴 하지만 가장 중요한 chroot 명령어가 없기 때문이다… 이는 WSL에 SSH 서버 돌리는 법에서도 언급했다.
docker 같은 크리티컬한 작업을 원한다면 가상 돌리는 게 훨씬 이득이다. 그밖에 가벼운 일반적인 사용 용도(node.js나 python 돌리는 등)에 WSL 쓰도록.

composite / 2018년 4월 24일 / Piss Development / 0 Comments

MacOS를 고민하는 개발자에게…

MacOS를 권장할 개발자

  • iOS 환경이 필요한 모바일 개발자
  • 크로스 플랫폼 개발자 (웹 제외)
  • 파이썬, 루비, 자스 등 스크립트 기반 언어 전문 개발자
  • 자동화와 키보드에 익숙한 개발자
  • 해외에서 개발할 개발자

MacOS를 쓰지 말아야 할 개발자

  • Eclipse 외에 안쓰는 자바 개발자
  • 전자정부로 먹고사는 개발자
  • Visual Studio 외에 안쓰는 닷넷/응용 개발자
  • Docker 등 컨테이너 위주의 개발자 (Docker 배포만 할 개발자 제외)
  • 심심할 때 게임할 개발자
  • 윈도우 7 이하 설치한 개발자
  • 마우스에 익숙한 애매한 개발자
  • 카공족

자바 개발자들, 이클립스는 리눅스에서 쓰기가 더 편하다는 거 알랑가몰라.(우분투 같은 GUI 기반)
만약 당신이 자바 개발자이고, 우분투 등의 리눅스 개발환경에서 자바 개발하는 선배 개발자를 만나면, 깍듯이 예를 대하거라. 보통 내공이 아닌 분이니라.

composite / 2018년 4월 18일 / Piss Development / 0 Comments

1 2 3 25