분류 전체보기 - 해당되는 글 382건

메르스(MERS)도, 사스(SARS)도 그저 먼 나라 이야기였다.

하지만 코로나는 바로 곁에서 현재 진행형이다.

지금을 일컬어 '코로나의 시대'라 불러줄 정도로, 코로나의 맹위는 수그러들지 않은채 여전히 그 영향력을 과시한다.

일시적이라고 생각했던 비일상은 어느새 일상으로 자리잡았고, 과거의 일상은 비상식이 되었다.

 

정부는 메르스에 대비해 '낙타와 접촉을 자제하세요'라는 비현실적인 대비책을 세웠고, 국민들은 매우 잘 지켰다.

코로나에 대해서는 '만남을 자제하고 사회적 거리두기를 하세요'라는 현실적인 지침을 전달했고, 국민들은 이를 지키지 못했다.

아니, 지키는 사람도 분명히 많지만, 지키지 않는 사람들이 유난히 돋보이는 건 어쩔 수 없는 현실...

 

나 하나쯤이야 괜찮겠지 싶어 거짓말을 한 사람들 덕분에 수십, 수백 배의 감염자가 나오고,

우리 정도는 괜찮겠지 싶어 예전처럼 모이는 사람들 덕분에 대부분은 비일상을 이어가는 중.

 

남 탓 하기 전에 일단 자기부터 잘 지키는 게 맞는 이야기다.

하지만, 감염 사례들 중에서도 우리가 잘 못지켜서 발생하는 피해자들 이야기가 그리 멀게만 보이진 않네...



Trackbacks  | Comments 

기록적인 폭염이 예정된 가운데, 냉장고 안 상태가 궁금하기도 하고, 정리도 할 겸...미뤄뒀던 샤오미 온습도계 값 읽어오기를 해봤다.

온습도 궁금하다고 냉장고 문 열어서 값을 읽으면 당연히 부정확하니까.

근데 막상 해보니까 생각보다 너무 금방 끝남;;;

 

* BLE가 되면 좋겠는데...하면서 생각 없이 봤더니 어? 되네? BT보다 편하겠네.

* 오 BLE...안잊어버렸어! 다 기억나!! 역시 인간은 고생을 해봐야.....

* 아니 이것들은 왜 멀쩡히 규격에 정의된 sensor profile 안쓰고 개나소나 자체 profile이야...라고 하기엔 좀 찔리긴 한데;;

* 지들이 만든거라 뭐가 뭔지 모르겠.........어라? 생긴게 ASCII같은데...? 어? 정말이다. 오...이걸로 걍 되네.

* SwiftUI는 참 편한데, 복잡한 경우는 잘 안될 듯. 어차피 gsync같은 걸 할 것도 아니긴 한데..Jetpack compose는 어떻게 될라나~

 

온도계 몇 개 더 살까...?

아예 위 아래 앞 뒤 다 넣어놓고, 차이가 심하게 난다 싶으면 fan도 강제로 돌리고...rpi나 남는 폰으로 아예 alert까지........는 당연히 귀찮;;;



Trackbacks  | Comments 

Java8에서부터, 그리고 Kotlin에도 lambda를 지원하면서, 익명 함수를 쓰는 경우가 대폭 늘어났다.

분명 작성해야 하는 code의 양을 줄여준다는 장점이 있지만, 익명 함수, 그리고 익명 클래스를 쓰는 건 VM입장에서 봤을 때 좋은 습관은 아니다.

 

이번에도 예를 들어, 달력 UI component를 만들 때 달력의 각 날짜에 onTouchListener를 붙인다고 가정해보자.

// 1월부터 그 달의 마지막 날까지
int lastDateOfTheMonth = getLastDateOfTheMonth();
for(int date = 1; date <= lastDateOfTheMonth; date++) {
	Date dateUI = new Date(date); // "날"에 해당하는 새로운 UI component를 만들고
    dateUI.setColor(...); // 기타 등등 설정을 하고
    dateUI.setOnClickListener((v) -> { parent.onTouchDate(date); });
    this.addDate(dateUI);
}

확실히 짧아서 좋은데, 문제는 이 code가 완전한 functional language 기반 위에서 수행되는 것이 아니라, JVM 위에서 수행된다는 점이다.

JVM 구현에 달려있긴 하지만, 위의 code는 일반적으로 아래와 같이 수행되는 셈이다.

// 1월부터 그 달의 마지막 날까지
int lastDateOfTheMonth = getLastDateOfTheMonth();
for(int date = 1; date <= lastDateOfTheMonth; date++) {
	Date dateUI = new Date(date); // "날"에 해당하는 새로운 UI component를 만들고
    dateUI.setColor(...); // 기타 등등 설정을 하고
    dateUI.setOnClickListener(new OnTouchListener() {
    	public void onTouch(View v) {
    		parent.onTouchDate(date);
        }
    });
    this.addDate(dateUI);
}

즉, setOnClickListener를 한 번 부를 때 마다 객체를 하나씩 생성한다.

위의 예에서는 달력이니까 30개 정도의 OnTouchListener를 만든다.

JVM에서 객체를 하나 만들면 거기에 따른 비용을 고려해야 한다.

더군다나 위의 예에서는 그냥 setOnClickListener(this)로 처리해도 되는 code인데....

 

게다가 요새는 UI 요구사항에 따라 하나의 class안에서 여러 개의 익명 함수, 익명 클래스를 만드는데, 간단한 code도 좋지만 성능도 성능이고, debugging 용이성에 미치는 영향도 잘 고려하는 게 필요하다.

물론, code 읽기도 편하고 쓰기도 편하겠지만, 어차피 같은 생명주기를 가지는 code들이라면 차라리 성능에 초점을 맞추는 걸 추천하는 편이다.



Trackbacks  | Comments 

개발자에게 가장 중요한 덕목에는 들어가지 않겠지만, 그래도 필요한 덕목 10가지 중에는 읽기, 쓰기가 들어간다.

거창하게 techincal writing이 아니더라도, 독해력은 간접적으로 programming에 꽤 많은 역할을 하고 있다고 생각한다. (programming도 결국 language로 하는 거라니까?)

 

그리고 많은 초보 개발자들이 "난 뭐 그 정도는 다들 알고 있는데"라고 하면서도 실천을 못하는 게 이름 짓기를 잘 하는 것이다.

변수, 함수, 하다못해 레이블을 하나 적더라도 이름을 지어야 한다.

이름 짓는 방법이야 이미 많고, 장점과 적용해야 하는 경우가 분명한데, 가장 중요한 건 "기준을 정하고 그 기준을 지키는 것"이다.

물론 여기의 기준에는 표기법도 포함되는 건 당연하다. 어디서는 camel case 적용하고, 또 다른 곳에선 hungarian 쓰고, 또 어디서는 섞어 쓰는 건 전체적인 일관성을 떨어뜨리고, 통일된 약속을 무너뜨려 결과적으로는 code를 읽고 해석하는 데 더 많은 자원이 들어간다.

 

그 중에서도 가장 기본적인 건, 변수는 명사로 짓고, 함수는 동사로 지어야 한다.

그리고 반드시 그 이름은 내용이 가리키는 바를 명확하게 명시해야 한다.

게다가 영어가 모국어가 아니니까 그렇다 쳐도, 그렇다고 요즘같은 시대에 internet에서 click 몇 번 하면 한영사전이 나오는데, "gogaek-bunho"라는 식으로 적혀있는 걸 보면.....

 

달력과 관련된 UI component를 만드는데, 처음에는 "padding"이라는 변수를 선언해두고, 나중에는 padding 계산이 날짜에 따라 바뀌는 code가 올라왔다.

자세히 보니, 그 달의 1일이 무슨 요일인지를 이 변수에 넣어두고, 이걸 이용해서 매월 "1"일을 왼쪽에서 빈 칸을 줘서 사용하는 것이다.

좀 양보해서 정확하게 그 용도로만 쓴다면야 상관 없을텐데, 이 변수의 값이 사실상 "그 달 1일의 요일 값"을 가지고 있다보니, 다른 계산들도 이 변수 값에 의지하게 되고, UI와 관계업는 내부 계산에서도 이 값을 의지하는 code까지 등장한다.

그럴 바엔 변수 이름을 애초에 바꾸는 게 맞는데, 처음 이름을 저렇게 지어놨으니 바꾸기 싫어하면.........

 

아무튼, 기초니까 이거 쉽네 하고 넘어가는 사람들이 꽤 많은데, 기초니까 잘 지키는 모습을 봤으면 하는 항목 중의 하나이다.



Trackbacks  | Comments 

조건문 얘기는 저번에 했으니...

if (1 <= someA && 9 >= someA && 1 == someA % 2) {
    someFunc(true);
} else if (1 <= someA && 9 >= someA && 0 == someA % 2) {
    someFunc(false);
}

정말 이런 걸 실전에서 볼까 싶은데도 방심할 수 없는 게 이 바닥이라..(사실 저번 else도 너무 당연한 거였지만)

위와 같은 code도 정말 자주 본다.

그래도 이 정도는 대부분 다시 생각 해보라고 하면 금방 아래처럼 가져온다.

if (1 <= someA && 9 >= someA) {
    if (1 == someA % 2) {
        someFunc(true);
    } else {
        someFunc(false);
    }
}

그런데 의외로 여기서 끝나는데...사실 이건 3항 연산자를 사용해주는 게 더 눈에 잘 들어온다.

if (1 <= someA && 9 >= someA) {
    someFunc( (1 == someA % 2) ? true : false );
    // Kotlin의 경우는 if를 쓴다.
    someFunc( if (1 == someA % 2) true else false );
    // 그리고 정말 이런 조건이면 3항 연산자를 쓸 필요도 없다.
    someFunc(1 == someA % 2);
}

뭐, 단순화 해놨으니 눈에 더 잘 보이는 거일수도.

 

그리고 동일한 형태의 함수 호출을 조건에 따라 여러 번 하는 건 가능한 자제하는 게 좋다.



Trackbacks  | Comments 

개발할 때 조건문 만큼 많이 쓰이고, 또 직관적인 구문이 또 있을까.

그런데 실용적인 측면에서 보면 쓰기 전에 한 번씩 잘 썼나 확인하는 구문이다.

조건문을 잘 쓰면, 보다 더 직관적이고, 간결하면서도 성능 좋은 결과물이나온다.

뿐만아니라, 안정성의 큰 줄기는 조건문에서 나온다고 본다.

그런 의미에서, 조건문을 쓸 때는 그 외, 즉 "else"일 때를 더 신경 써줘야 한다.

 

switch(transmissionType) {
    case manual:
        // 처리
        break;
      
    case automatic:
        // 처리
        break;
        
    case unknown:
        // 처리
        break;
}

자동차의 변속기 종류에 따라 처리하는 code를 작성한다고 가정해보자.

만일 transmissionType이 enum 형의 변수라면 위의 구문으로 충분할 수도 있다. (IDE에 따라 모든 경우가 없다고 자동 경고해주기도 함)

그런데 만일 int형이라면, 혹은 다른 machine에서 전송받은 값을 처리해서 enum으로 바꾸는 구문이라면 위의 경우는 문제가 될 수 있다.

위의 transmissionType의 변수에 정확히 저 3가지 값만 들어오라고 강제할 수 없는 경우는, unknown을 차라리 else나 default같은 fallback 처리를 넣어주는 게 좋다. (비정제 data 분류할 때도 자주 이렇게 한다)

 

물론, 지정한 3가지 값 이외의 숫자가 들어오는 것 자체가 문제다. (그래서 추가로 예상치 못한 값이 들어왔을 때의 처리를 해야 함)

상황에 따라 다르겠지만, 모르는 값이 들어와서 아예 처리를 하지 않는 경우와, 기타의 경우로 대치하여 처리를 계속 하는 경우가 각각 필요한 경우가 있다.

적어도, 아예 비정상 종료를 하거나, 원치 않는 동작을 하는 것은 미리 막아두는 게 제일 낫다.



Trackbacks  | Comments 

Java에는 Serializable이 있어서, 다른 thread나 다른 processor, 혹은 다른 machine에 object instance의 상태를 그대로 복사할 수 있다.

물론 다 되는 건 아니고, 당연하지만 다른 object reference를 옮길 수는 없고, 주로 data class의 내용을 쉽게 옮기는 데 사용한다.

 

그래서 Serializable을 쓴 code에 이걸 왜 썼냐고 물어봤더니, 대답은 "쓰기 쉽고 간편해서"라고 한다.

하지만 Serializable은 reflection을 사용해서 전송한다.

 

reflection을 사용하게 되면 보통 나오는 문제는 당연히 속도 저하.

뭐 이거야 짧게 쓰면 큰 문제가 안되는 경우도 있으니..

 

그리고 두 번째는 난독화에 걸리면, 각 field 이름이 제멋대로 변한다.

이 경우는 같은 binary를 사용한다는 전제하에, 바뀐 이름을 공유하게 될테니 넘어갈 수도 있고..

 

Android의 경우는 Parcelable이 있어서, Serializable과 거의 같은 용도로 사용할 수 있다.

대신, Parcelable의 구현에는 reflection을 사용하지 않는다.

 

Serializable의 경우도, writeObject(), readObject()를 직접 구현하면 적은 overhead로 동일한 동작을 할 수 있고, 별도의 추가 처리도 직접 넣을 수 있다.

대신 약간의 bytecode가 더 늘어나지만, 가능하면 Serializable을 사용할 때는 writeObject(), readObject()등을 함께 구현하는 습관을 들이는 걸 추천.

 



Trackbacks  | Comments 

iOS의 UIColor의 생성자 중, RGB값을 사용하는 생성자는 다음과 같다.

init(red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) // 참고 : https://developer.apple.com/documentation/uikit/uicolor/1621925-init

각 색상값들의 변수형이 CGFloat인 이유는, 0 ~ 1.0 사이의 값으로 지정하게 되어 있기 때문이다.
하지만 개발업무에서 대부분의 색상값 전달은 hex 혹은 int를 사용하다보니, 애초에 iOS 용도로 나온 안내가 아니라면 불편한 경우가 많다. 사실, 따져보면 iOS도 최소한 driver 수준에서는 정수를 사용하고 있을텐데.
어쨌든, 이번에도 designer들에게 전달받은 색상값이 전부 정수로 되어있다보니, 이걸 공통함수화 하겠다는 commit이 올라왔다.

func UICOLOR_RGB(_ r: CGFloat, _ g: CGFloat, _ b: CGFloat) -> UIColor {
	return UIColor.init(red: r/255, green: g/255, blue: b/255, alpha: 1)
}

 

함수명을 대문자로 한 이유는 “UICOLOR 값 세팅이기 때문에 함수명을 대문자로 작성” 이라고 한다.
이건 기존에 명명규칙 등을 정의한 개발안내서를 참고하라는 이야기와 함께 기각.

Extension을 쓰는 게 낫지 않겠느냐는 이야기엔...”그게 더 번거로울 거 같아서”라고.
이건 가능하면 extension으로 생성자 추가하는 게 나을거라는 이야기는 했지만, 선택은 본인 몫이니 알아서 하라고 했다.

매개변수를 실수가 아니라 int처럼 정수 계열로 하는 게 낫겠다는 건...납득은 못한 분위기다.
그래서 이건 꼭 바꿔야 한다고 기각했고, 곧 “float가 아니라 int면 나누기가 안됩니다. 제가 뭘 못하는건지 계산 값이 제대로 이루어지지않아 검정색으로 나옵니다(0으로 처리) 그래서 CGFloat으로 두었습니다. 해결방법있으면 알려주세요~” 라고 한다.
.......순간 암담했지만, 말로 쓰기보단 type casting 관련 link를 보내줬다.

해당 PR에는 아래와 같은 예제 구문을 남겨두었다.

extension UIColor {
	convenience init(_ r: UInt8, _ g: UInt8, _ b: Uint8, _ a: UInt8=255) {
		self.init(red:CGFloat(r) / 255.0, green:CGFloat(g) / 255.0, blue:CGFloat(b) / 255.0, alpha: CGFloat(a) / 255.0)
	}
}



일단 변수형을 UInt8로 제한했다. 아래 생성자 구문에서 볼 수 있다시피, 각 값은 0 ~ 255의 범위를 갖는 RGB888 체계를 사용한다고 가정했기 때문이다. 표현값의 범위가 UInt8과 정확히 일치하기 때문에, 변수형을 제한시켜두면 compile time에서 잘못된 값을 넣는 걸 방지할 수 있다.
마지막 alpha에는 기본값을 255로 넣어두어, 필요한 경우 생략해서 사용할 수 있게 했다.
그리고 extension으로 생성자를 추가했기 때문에, 보다 더 직관적으로 사용할 수 있지 않을까?

 

하지만 이 사진구문이 사용되는 일은 없었다.
대신 올라온 code가 어떤지, 그냥 기록 삼아 남겨두자......

func UIColor_RGB(_ r: Int, _ g: Int, _ b: Int) -> UIColor {
	let red: CGFloat(r)
	let green: CGFloat(g)
	let blue: CGFloat(b)
	return UIColor.init(red: red/255, green: green/255, blue: blue/255, alpha: 1)
}


Trackbacks  | Comments 

신촌에 있는 벨기에 레스토랑.

낮에는 샌드위치 같은 식사를 팔고, 저녁엔 치킨이나 감자튀김같은 안주류와 술을 파는 곳인 듯.

아, 물론 낮에 술 주문해도 팔겠지만. -_-a;;


메뉴판 펼쳐보니 은근 가격대가 나가는 편이다.

세트메뉴를 시킬까 했다가 ,지갑님이 감당하기 어려울 것 같다는 판단에 저렴한 샌드위치만 두 종류 시켜먹음;;



분명 샌드위치만 시켰거늘, 갑자기 스프가 나왔다!

헉~ 일부러 런치 세트 말고 샌드위치만 시켰는데...이거 혹시 세트로 들어간건가? 하는 생각이, 나중에 계산할 때 막 "잔액부족" 뜨는 장면까지 순식간에 진행된다.

그래서 물어봤더니, 점심 때 시키면 원래 스프를 같이 준댄다. =ㅅ=;; 아 그러쿠나~




그리고 뒤이어 나온 불고기 샌드위치.

필리치즈랑 비슷한 느낌인데, 빵이 바케트 빵이라 더 단단하다.

그래서 좀 더 바삭바삭한 씹는 느낌이 강하면서도, 고기랑 치즈의 끈적한 맛을 느낄 수 있다.

야채따윈 필요 없다! 샌드위치라면 역시 소화 잘 되는 고기! 라는 사람에게 어울림. -ㅅ-/




그리고 이건 뽀빠이 샌드위치.

이름에서 짐작할 수 있듯이, 사진에 보이는 녹색 잎은 시금치다.

그래도 샌드위치에 야채만 들어가면 (그 비싼 돈을 내는 게) 섭섭하니까, 안에 치킨도 들어가있음.


두꺼우면서도 딱딱한 바케트 빵인데도 재료의 식감이나 맛을 잘 살리는 샌드위치들이라 먹을만 했다.

역시 문제라면 가격...=ㅅ=;;;

가격이 좀 더 싸진다면 가볼만 할텐데~~~



Trackbacks  | Comments 

노트북에 달아줄 SSD를 찾아보다가, 이번엔 플렉스터 M5 Pro 512G를 질렀다!

이미 메인 PC에서는 SSD를 예전부터 쓰고 있다보니, 노트북에서 그 답답한 속도를 도저히 참지 못하겠더라.

그래서 때마침 생긴 여유 자금을 여기에 다 붓고, 비운만큼 마음이 너그러워진다는 그 길을 따르기로 했다. -_-;;; 이래서 또 은행 잔고는 하향선 유지.


어쨌든.

애초에 삼성의 마케팅 실력을 굳게 믿고 있는데다가, 삼성 SSD 멋모르고 샀다가 피본 사람들을 여럿 알고 있기도 하고, 개인적으로 좋아하지도 않으니 일단 제외.

물망에 오른 건 Intel / Plextor / OCZ 정도였는데, 이리저리 찾다보니 결국 Plextor가 개중 나아보인다.



 

Plextor M5P

Samsung 840

OCZ Vertex4

 Intel 520

 Sandisk

 용량

 512 GB

 500 GB

 512 GB

 480 GB

 480 GB

 순차 읽기

 540 MB/s
 540 MB/s

 560 MB/s

 550 MB/s
 540 MB/s

 순차 쓰기

 470 MB/s
 330 MB/s

 510 MB/s

 520 MB/s

 460 MB/s

 무작위 읽기

 100,000 IOPS
 98,000 IOPS

 95,000 IOPS

 50,000 IOPS
 44,000 IOPS

 무작위 쓰기

 88,000 IOPS

 70,000 IOPS

 85,000 IOPS

 50,000 IOPS

 46,000 IOPS


간단히 정리해 본 각 SSD별 수치 비교.

결과는 Plextor M5P로 낙찰이다.


그래서 질렀음. -ㅅ-;



주문하면 이렇게 생긴 상자에 온다.

상자 전면 좌측 중간에 있는 홀로그램 스티커가 국내 공식 유통사인 컴포인트의 정품 스티커. 이거 버리면 해외제품처럼 A/S 안해주려는 듯. 잘 떼서 SSD 본체에 붙여두는게 좋다.



봉인라벨이 훼손되면 내용물을 책임지지 않는다는 봉인 스티커. 당연하지만 이게 뜯어져있거나 없으면 새 제품이 아님. -ㅅ-a


제품을 뜯으면 저렇게 생긴 SSD가 나온다.

뭐 SSD 외양이야 다 거기서 거기고, 무게도 거기서 거기.

Plextor 제품은 바깥 재질(하우징)이 알루미늄에, 헤어라인 처리가 들어가 있다.

개인적으론 금속 재질 + 헤어라인 처리를 매우 좋아함.

어설프게 플라스틱에 헤어라인 처리한 제품은 정말 싫어함. -_-;;; (대표적으로..아니 생략;;)


뚝딱 설치하고 벤치마크를 돌려봤다.



성능도 잘 나온다.


노트북에 꽂을 제품이다보니 일단 대용량으로 질러두긴 했는데, 노트북이 좀 예전거라 제성능이 다 나오지는 않는 듯.

그래도 SSD는 나중에 노트북 새로 사더라도 옮겨서 꽂으면 되니까. =ㅅ=a;;

SSD도 NAND Flash인지라 wear-out 현상이 필연적인데, 과연 어느 정도의 안정성이 나올지는 차차 쓰면서 확인하는 수 밖에 없다.

현재까지는 매우 높은 만족도를 보여주는 플렉스터의 SSD! :D



Trackbacks  | Comments