2021년 목표설정

이미지
기본적으로 작년에 달성하지 못한 것들을 하려고 생각중인데..코로나가 언제까지 이어질지, 한국이나 북해도는 갈 수 있을지..자격증은 응시 가능할지..여러가지가 불확실하다. 2021년은 무엇보다 정신적인 부분과 경제적인 부분에 중점을 두고 조금 더 치열하게 지내보고 싶다. 일본나이로도 30대 마지막 해, 이제 불혹에 접어드는 나이..복잡하지만 심플하게. 육체적목표 : 트라이에슬론 스탠다드 도전하기 정신적 : 자격증2개 도전 + 자체개발 서비스 론칭 가족적 : 가정의 평화를 유지하기 경제적 : 외식과 유흥비를 줄이고 부수입을 늘려서 결과적으로 저축하기 사회적 : 목표세미나를 포함해서 민단과 개인인맥의 활성화와 교류를 촉진하기

엔터프라이즈 환경 입문 Java 개발자를 위한 3가지 조언

엄청난 동시 사용자, 처리되지 않는 예외상황들, 끝없이 늘어가는 메모리 사용량, 이유를 알 수 없는 장애발생...
엔터프라이즈 환경의 개발자는 이만저만 피곤한 게 아니다.
경험 많은 선배 개발자가 엔터프라이즈 환경에서 Java 프로그램을 개발할 때 견지해야 할 기본 원칙을 들려준다.
늘 환경의 차이를 염두에 두어야
처음 Java로 개발할 때는 지금처럼 웹 프로그래밍을 하지는 않았다. 예제도 Windows에서 실행되는 애플리케이션이 많았고(AWT로 개발하다가 Swing이 나왔을 때 감탄하던 기억이 새롭다.), 한창 개발에 재미들이던 그런 시절이었다. 하지만 그렇게 재미로 개발하다가 직장에 들어가 서버 애플리케이션을 개발하게 되었을 때는 재미로 개발할 때는 신경도 쓰지 않았던 각종 이슈로 밤을 지새게 되었다. 엄청난 동시 사용자, Catch가 되지 않은 예외상황, 끝없이늘어가는메모리사용량, 계속이유를 모르게 죽는 컨테이너 등등... PC에서 GUI 프로그램을 만들 때는 생각해 보지 않은 이슈들이 너무도 많았다.
이런 경험은 대다수의 엔터프라이즈 개발자들이 초보 시절에 공통으로 겪는 어려움일 것 이다. 사실 개발자들이 관심 많았던 방법론이나 TDD 같은 많은 기법들은 PC에서 작은 애플리케이션을 개발하는 개발자에게는 여름 철의 모피 코트 같이 불필요한 겉치레일 수 있다. 하지만 PC에서 개발하다가 엔터프라이즈급 시스템에서 개발하게 되었을 경우에는왜 방법론이 필요하고, 왜 개발중 테스트가 중요한지 피부로 느끼게 된다.
그렇다면, 초보 개발자들이 왜 엔터프라이즈급 시스템에서 개발하는 것이 힘들까?
필자는 그 이유를‘환경의 차이’라는 관점에서 풀어가고자 한다. 개발자가 코드에 쏟는 정성과 코드 개발의 원칙들이 잡지와 웹을 통해 많이 소개되고, 요즘은 프레임워크 Framework)와 SOA(Service Oriented Architecture) 같은 새로운 패러다임이 등장하고 있지만, 우리가 만드는 애플리케이션은 필연적으로 환경에 종속적이다. 이런 환경을 아예 모르고 개발하는 것과 환경에 대한 이해를 바탕으로 개발하는 것은 결과에서 차이가 날 수 밖에 없다.
하드웨어와 운영체제의 차이
요즘은 PC도 64비트 급이 나오고 있지만, 대다수PC는32비트의 Intel 기반이나 AMD 기반의 칩을 사용하고 있다. 하지만 대다수 엔터프라이즈급 시스템의CPU는이런32비트PC급에서 사용하는 칩이 아니다. 전부64비트이고 평소에 잘 듣지도 본 적도 없는 칩들(PA-xxxx, Itanium2, P5, UltraSPARCIV,...)이다. 어떤 독자는 이렇게 반문할 것이다.
“Java 개발자인데 어떤 CPU를 쓰던 어떤 운영 체제를 쓰던 무슨 상관이죠?”
Java의 최고 장점이‘Write Once, Run Anywhere’라고 하니까CPU와 운영체제가 하등 문제될 게 없다고 생각하겠지만, 이 말대로100% 된다고 보기 힘들다. PC에서 가동되는JVM은Superdom이나 E20k 같은CPU가 64개나 되는 시스템의 UNIX에서 가동되는 JVM과는 많은 차이가 있다.
그리고 JVM도 특정 JVM의 경우에는 지원되는CPU와 운영체제가 한정되기도 한다(JVM은 해당 운영체제에 맞추어 C로 만들어진 애플리케이션이다).
또, Java 개발자가 사용하는 모든 애플리케이션이다 Java는 아니다. 우선적으로 DBMS가 Java가 아니다.
물론 JDBC를 통해 접근이 가능하니까 관계없겠지 하겠지만, 특정 애플리케이션의 Java 어댑터가 HP-UX만 지원한다든지 Sun만 지원한다든지 했을 때는 참 난감하지 않을 수 없다. Java 개발 자체가 힘들어질 수 있는 상황이 된다(실제 필자의 경우 특정 XML DB의 어댑터가 Linux를 지원하지 않아 곤란을 겪은 적이 있다. 프로젝트 막판에 이걸 알게 되면배로 힘들어지면서 프로젝트의 성공여부가 불투명해질 것이다). PC에서 솔루션 개발하고 Linux에만 포팅해도 여러 문제가 발생하게 되는데 이걸 또다른 플랫폼에 포팅했을 때는또다른문제를유발할수있다는점을꼭명심해야한다. Java는 다른 언어보다 이런 포팅에 있어서 비용이 확실히 적지만 전혀 없다고 할 수는없다.
이런 플랫폼과 시스템의 차이 외에 실제 가동될 환경과 PC 환경의 차이로 인해 테스트 측면에서도 문제가 발생 할 수 있다. 예를 들어, 초당4000 건의 데이타를 처리하는 프로그램을 개발하는 개발자가 PC 환경에서 이런 프로그램을 개발하고 테스트할 수는 없다. 개발할 수 있는(물론 테스트할 수 있는) 환경에 따라 개발자의 개발 스케일도 변할 수 밖에 없다.
시스템 구성환경의 차이
PC나 개인서버 (대다수가Linux 서버)에서 개발 할 경우 잘되던 프로그램들이 왜 회사에서 사용하는 대규모 시스템에 올라가면 정상적으로 작동하지 않는 것일까?
일반적으로 서비스를 처음 시작하는 조그만 사이트에서는 한대의 시스템에 웹서버와 컨테이너, 그리고 DBMS를 같이 운용하게 된다. DBMS는 다른 시스템으로 분리하는 경우도 있지만 대개가 이런 구성이다. 하지만 사용 고객만 수백만 명인 사이트의 경우, 이런 구성으로는 애초에 서비스가 불가능하다.
우선 보안 문제와 시스템 리소스의 적절한 분배를 위해서 전단 방화벽과 후단 방화벽 사이에DMZ를 구성하여 웹 서버를 두고, 후단 방화벽 뒤에 WAS와DBMS를 두는 구성으로 분리하게 된다. 웹 서버와WAS가 같은 위치일 경우에도 DBMS는 후단 방화벽 뒤에 있는 경우가 많다. 또 WAS와 DBMS을구성할때, 시스템 리소스를 많이 필요로 하는 애플리케이션의 경우 시스템을 분리하여 한쪽에 부하가 발생해서 두 시스템이 다 장애 상황에 빠지지 않도록 구성한다. 또한 웹 서버, WAS, DBMS의 이중화 및 클러스터 구성도 고려해야 한다.
자! 그러면 이런 환경에서 발생할 수 있는 문제들은 무엇일까?
예상 문제 1 : 방화벽
우선 문제될 수 있는 부분이 방화벽이다. 방화벽은 정말 필요한 부분을 제외 하고는거의모든포트와접근IP를제한하고있다. 한 시스템에서 작동하는 웹서버와 WAS가 중간에 방화벽을 두고 통신하게 되었을 때 문제가 발생하면, 방화벽의 룰셋을 점검해 보는 게 좋다. 서버의 환경 설정에도 문제가 없는데 통신상 에러가 발생하는 경우 십중팔구는 중간에 방화벽으로 인한 통신 장애가 많다. 이건 웹 서버와WAS 간, WAS와DBMS 간에도 발생할 수 있다.
대다수의 방화벽에는 80포트를 제외한 모든 포트를 막고 있고 필요에 따라 인바운드, 아웃바운드로 구분하여 IP에 따라 개방하고 있다. 따라서 웹 서버와 WAS간 통신을 위한 포트(Tomcat 같은 경우 8080, 모 WAS의경우 7101번,...)가 열려 있어야 한다. 또한 WAS와 DBMS간 연결을 위해DBMS의 리스너 포트도 열려 있어야 한다(Oracle Database Listener Port 1542번).
예상 문제 2 : 업로드나 저장된 파일의 처리
또 문제될 수 있는 부분이 업로드나 저장된 파일의 처리이다. 웹에서 ‘파일 업로드’에 의해서 저장된 파일의 경우, WAS가 위치한 서버의 파일 시스템에 위치하게 된다. 문제는 이중화 구성에 의해 2대로 존재하는 시스템에 어느 한 쪽에만 위치하게 된다는 점이다. 해당 파일에 접근하는 클라이언트는 2대의 시스템 중 어느곳으로 접근할지 알 수 없다.



이럴 경우 해결 방법은 여러가지를 고려해 볼 수 있다. 다른 시스템에 복사를 통해 파일을 이중으로 관리할 수도 있고, 프로그램을 통해 파일에 따라 접근하는 시스템의 경로를 지정해 줄 수도 있다.
이런 해결책 중에 프로그램을 통해 파일에 따른 접근을 시도 할 경우, 시스템이 늘어날 때 프로그램을 수정해야 하는 문제가 발생하고, 특히 형상관리가 안되던 시스템을 이관하려고 할 때 해당 업로드 파일과 DB에 남아 있는 위치 정보가 안맞아 시스템 이관시 큰문제를 야기할 수 있다. 또 다른 시스템에 파일을 복사해주는 방법의 경우, 두파일의 정합성을 보장하기가 사실상 힘들 수 있다. 이걸 소스 단에서 고민하기 시작하면 이슈가 될 부분이 많이 발생하게 된다.
가급적이면 스토리지(NAS 등)를 통한 물리적 공유 방안을 통해 한개의 파일을 관리하라고 권하고 싶다. 물론 비용 문제가 발생할 수 있지만, 다른 해결책은 문제점을 내포하고 있고, UNIX의 NFS 등의 방법은 한쪽 노드에 문제가 발생했을 경우 정상적인 노드도 문제를 야기할 수 있고 보안에 취약하여 권장 할 수 없다. 따라서 추후의 유지보수를 위해서 도 물리적 공유가 좋은 방안이 될 것 이다.
이런 파일 중에 인증이 필요 없는 업로드된 파일은 가급적 웹 서버쪽으로 보내주어 WAS까지 오지 않도록 해주는게 WAS에서 I/O를 줄일 수 있다는 점도 고려해 볼 수 있다(WAS상에는 파일을 열 수 있는 최대파일 수가 정해져 있어서 파일이 큰 경우 I/O가 열려진 상태로 다른 커넥션이 증가할 경우 피크타임에는‘Too Many File Open’으로 정상 서비스가 힘들 수 있다.
하지만 현재 이슈가 되고 있는, 컨텐츠 보호가 필요한 파일들의 경우에는 URL 변경을 통한 보호가 필요하므로, 웹 서버쪽에 올리는 건 문제가 될 수 있어 해당 업무에 따른 적용의 묘를 살려야 할 것이다.
예상 문제 3 : 클러스터 구성
또 고려해야할 점은 클러스터 구성이다. 클러스터는 쉽게 이야기해서 여러 독립적인 노드를 단일 시스템으로 작동하는 것처럼 하나로 묶는 기술이다.
클러스터는 고가용성과 로드 밸런싱의 장점, 페일오버 처리 등으로 엔터프라이즈 환경에서 각광받고 있는 기법이다. 현재 대다수의 대형 사이트가 클러스터로 운영중이라고 봐도과언이 아니다. 이게 개발자랑 무슨 관련이 있을까?
WAS에서 클러스터링은 RMI라는 하부 프로토콜을 이용하여 WAS의 세션 복제 등을 처리하고 있다. RMI로 분산객체 프로그램을 해본 프로그래머들은 알겠지만, 리모트로 객체를 주고 받아 본 개발자들은‘Serializable’ 이라는 말이 사무칠 것이다.
사례를 보면서 한번 보도록 하자.
모 쇼핑몰이 전자상거래 활황으로 그 동안 한 대에서 운영하던 쇼핑몰을 WAS 서버를 추가하면서 두 대를 클러스터로 연결하고 가동을 시작했는데, 고객의 로그인이 중간에 끊어지고, 장비 중 한 대가 문제가 생겨도 페일오버될 거라고 생각했는데 문제 장비에 접속해 있던 사용자들은 다 세션이 없어지는가 하면, 장바구니의 물건이 사라지는 일이 벌어졌다. 멀쩡하게 잘 작동하던 애플리케이션이 갑자기 왜 이럴까? 개발팀에서 누가 소스를 변경했나 확인 해봤지만 바꾼 사람도 없었다. 우선 급하게 로그들을 살펴보기 시작했다. 그랬더니 전에 못보던 에러 메시지가 눈에 띄었다.



혹시나해서 소스를 살펴보기 시작했다.



이런 부분들을 발견했다. 이 소스에서 문제점은 ShoppingCart 클래스 이다. 앞에서 설명했듯이 두 대의WAS에서 세션이 메모리 내 복사를 통해 동기화할 경우 RMI를 통해 복제가 일어나게 되는데, 위에서 세션에 넣은 ShoppingCart는 별다른 구현이 없는 단순한 bean 클래스이지만 Serialize 한 객체가 아니므로 세션복제 중에 복사를 못하면서 발생되는 문제이다. 이 건 아래와 같이 수정해주면 간단히 해결된다.





하지만 이렇게 해결한다고 하더라도 세션데이타를 Serialize하면 세션복제로 인한 오버헤드가 발생하게 되고 이렇게 Serialize된 개체의 크기가 커지면 커질수록 오버헤드도 증가한다. 따라서 가급적이면 세션에 아주 큰 개체를 사용하는 경우는 피하는게 좋다. 아무리 물리메모리가 많다고 하더라도 웹 시스템은 피크 타임에 들어오는 커넥션을 예측할 수 없고, 해당 Request에 대한 처리가 지연되면 그만큼 메모리를 점유하는 시간은 길어지 기마련이다. 메모리는 항상 제한된 자원이라는 생각으로 접근하는게 좋다.
대형 시스템에서 풀(pool)을 많이 사용하는 이유는 아무리 대형 시스템도 자원은 항상 제한적이라는 관념을 가지고 개발하기 때문이다.
클러스터에서 세션을복제할 때 발생하는 오류는 개발자가 클러스터 환경에 대한 이해를 전제로 프로그래밍하는 방법외에는 별다른 방법이 없다.
필자도 통신회사나 대규모 금융회사의 시스템에 개발을 해보았지만 대개의 경우 운영환경이 이렇게 이중으로 구성되어 있는 반면, 개발계 시스템이나 검증계 시스템의 경우 단일 시스템으로 운영되기 때문에 실제 운영에 적용하고야 그 문제점을 알 수 있는 경우가 많다. 금융권에서 고참개발자들이 개발에 대단히 신중한 이유는 이렇듯 실제 운영에 반영하고서야 문제점이 발생하는 경우를 많이 경험했고, 이런 문제점이 대형 사이트에서는 얼마나 치명적인지 잘알고 있기 때문이다.
모든 자원을 근검절약해야
Linux나 개인PC에서 루트(root)를 가지고 개발하는 개발자들이 대형사이트에서 개발할 경우 상당히 답답하다고 호소한다. 그도 그럴 것이 루트를 가지고 뭐든지 환경을 바꾸고 유저를 만들고 포트 열 거 다 열어가면서 개발하다가 대규모 사이트에서 개발할 때는 우선 시스템의 관리 주체가 다양해 그 절차에 한숨짓게 된다. 흔히 시스템에 대한 루트는 데이타센터에서 실제 운영체제 및 하드웨어를 관리하는SE들이 가지고 있으므로, 그 윗단에서 개발하거나 접근하는 개발자들은 일정한 절차에 의거해서 할당받은IP, 할당받은 포트만 이용해야 한다(물론 이런절차는 수일에서 심지어 일주일이 걸리기도 한다.) 또 기존 운영체제에서 사용하는 라이브러리도 확인해야 하고, CMS나 이런 툴 또는 개발 및 관리 프레임워크가 있을 경우에는 이에 따라 개발 방향도 바꾸어야 한다. 게다가 시스템에 대한 이해의 시간도 가져야 한다.
이럴 경우 계획했던 개발 기간은 상당히 압박을 받게 된다. 이건 프로젝트가 막바지에 다다른 시점에도 계속된다. 인수 테스트에서 부하 테스트 및 보안이라는 이슈로 인해 대규모 변경이 발생할 수도 있다.
최신 기술의 개발 방법보다는 안정성과 보안성이 더 중요시되는게 엔터프라이즈 환경이다. 엔터프라이즈 환경이 대규모 시스템 환경이라 하지만 웹에서 갑자기 몰려드는 사용자를 다 처리할 수 있는 시스템은 존재하지 않는다. 다만 제한된 범위에서 지속적인 서비스를 가능하게 하는 시스템이 있을 뿐이다. 이런 지속적인 서비스를 가능하게 하는건피크타임에 시스템 자원을 어떻게 적절히 안배하고 임계치에 이른 Request를 어떻게 처리하는가에 달려있다. 여기에 선행되어야 할 것이 각종 자원에 대한 지속적인 모니터링과 이를 통한 지속적인 소스 관리 이다.
메모리
수십 GB의 메모리를 보유하고 있다고 하더라도, 시스템을 구현한 직후에는 소스에서 자원 할당을 받고 반환하지 않는 부분들로 지속적으로 메모리가 증가하는 경우가 많다. 특히 Java는 메모리를 직접 관리하지 않는다. JVM에서 GC 알고리즘에 따라 관리하니까 신경 쓸 필요가 없다고 생각하는 개발자의 경우 이런 자원에 대해 부주의 하기 쉽다.
수 GB에 해당하는 메모리에 있는 객체를 GC 할 경우 어떤 일이 발생하는지 알고 있는가? 위의 개발자 말대로 JVM의 GC 알고리즘이 지속적으로 향상되고 있는 것은 사실이다. 하지만 GC가 발생하여 수 GB의 객체가 GC가 될 때 WAS는 일시적으로 정지 상태에 이르게 된다. 메모리에서 릴리스 하는 동안 WAS는 아무 일도 못하는 상태에 빠지게 된다. 이런 상태에서 자주 이런 일이 발생하게 되면, 시스템에 접속하는 사용자들이 불안정한 접속으로 고통받게 된다.
그리고 자동화(GC)라는 편안함에 안주해선 안된다. GC는 만능이 아니므로 비사용중인 메모리는 다회수할 것 같지만 절대로 그렇지 않다. 따라서 사용이 끝난 레퍼런스는 꼭Null로 처리해 주어서 명시적으로 GC를 유도하는 것이 좋다.
그리고 지속적으로 메모리를 모니터링하여 SWAP이 지속적으로 늘고 있는건 아닌지, 사용하고 있는 실제 메모리가 늘고 있는지 확인해 볼 필요가 있다. 필자의 경우, 특정 Java 프로그램에서 지속적인 메모리 증가가 보여 추적해 보니, 해당 프로그램에서 JNI를 통해 호출하는 C Lib에서 누수가 일어나고, 이로 인해 지속적으로 메모리가 증가하는걸 본 적이 있다. 이 경우 해당 Lib를 패치하고서야 정상을 찾을 수 있었지만 이런 경우는 어디서나 발생할 수 있는 문제이다. 지속적인 모니터링을 통해서 관리해 나가야 한다.
소켓
대다수 개발자들이 알다시피, 운영체제에서 소켓은 파일과 동일하게 처리된다. 임계치에 도달한 WAS에서 ‘Too Many File Open!’ 이라는 메시지를 보았을 때는 우선 파일을 기록하는 파일 I/O쪽도 의심해 봐야겠지만, 해당 시스템의 쓰레드 덤프를 통해서 얻어진 자료를 통해 파일이 많이 열린 것인지, 소켓이 많이 열린 것인지 확인해 보아야 한다.
WAS 환경에서 개발하는데 소켓을 열 일이 얼마나 있겠나 하겠지만, URL 접속이나 이런 피치 못할 소켓 연결을 사용하여 구현한 페이지의 경우 조심해야한다. 해당 페이지에서 이런 소켓 연결을 생성하는 경우가 되면, 해당 페이지에 접근하는 모든 쓰레드에서 소켓을 열게 되고, 이것이 이벤트 등의 성격을 띤 페이지일 경우 위와 같은 메시지를 뿌리면서 시스템이 정상 가동을 못하게 된다. 페이지에서 직접적으로 소켓을 열지 말고 Pool 등의 메커니즘을 사용한 객체를 만들어쓰고 반환하는 식으로 접근해야 한다.
파일
파일도 소켓과 마찬가지이다. 역시 제한된 자원이라는 개념으로 접근해야 한다. 요즘 많이 사용하는 Log4J나 다른 로그 프레임워크들을 살펴보면, 대개는 같은 컨셉을 가지고 있다. Singleton으로 구현된 Logger에 다양한 방식의 아웃풋을 지원하고, 설정한 로그 레벨에 따라 로그를 기록하는 것을 볼 수 있다.
Log4J의 경우 Category나 그서브클래스인 Logger에 다양한 Appender를 추가하여 다양한 출력방식을 지원하도록 되어 있다. 문제는 이걸 그대로 사용하지 않고 Wrapper 클래스로 이런 Log4J를 구현했을 때 문제가 발생할 수 있다.
예를 들어 보자. WAS에서 고유하게 제공하는 로깅 서비스가 있지만 Log4J를 사용해서 DailyLog라는 클래스를 만들고 JSP 페이지에서 로그를 남길 경우 이 클래스를 사용한다고 가정하고 아래 소스를 보자.
이 클래스를 통해 로그를 기록하게 되면 문제가 될 수 있는 부분은 Appender의 지속적인 증가이다. 위에서 로그 클래스를 접근하는 쓰레드마다 정적인 로거에addAppender를통해Appender를 추가하게 된다. 이런 현상이 지속되면, DailyLog.log라는 파일에는 여태껏 계속 붙었던 Appender가 각각 한 라인씩 쓰게 되고 수십 개의 I/O가 한 번에 발생하게 된다.
세션
마지막으로 절약해야 할 부분은 의외로 실천사항이 간단한 세션이다. 세션 내에는 많은 데이타가 들어가게 된다. 이런 데이타가 중복되는 경우는 특히나 특정 시스템을 여러 개발자나 여러 개발사가 개발하게 되면서 가중된다.
실례로 세션에 가장 많이 담는 정보 중 하나가 고객의 주민번호인데, A 개발자는 SSN이란 값으로 저장하고, B 개발자는 Jumin으로 썼다고 할 경우 동일 정보가 세션내에 지속적으로 상주하게 된다. 이런 경우는 개발 초기에 분리해 개발하면서 개발 원칙과 세션내 데이타에 대한 표준을 정하지 않고 개발에 착수할 때 특히 빈번하게 발생한다. 또 개발한지 오래된 시스템에서 개발 주체와 운영 주체가 계속바뀐 시스템에서도 많이 볼 수 있다. 앞에서도 언급했지만 가급적이면 있는 정보에 대해서는 재사용을 하고 세션처럼 다른 개발자들도 많이 쓰는 부분에 있어서는 담당자를 정하고 그 사람을 통해 관리하는 것이 바람직하다.
환경을 고려한 개발
필자는 대규모 빌링 시스템의 개발에도 참여했었고 현재는 유지보수를 담당하고 있다. 업무가 바뀌면서 가장 크게 느꼈던 점은 소프트웨어는 개발이 끝이 아니고 요구사항이 변해감에 따라 항상 변해가는 유기체라는 점이다. 특히나 대형 시스템의 경우, 일정 시점에서 스냅샷을 찍었을 경우 외에는 지속적으로 변해가는시스템이다.
이런 시스템을 개발하고 유지보수하면서 필자는 환경적인 고려 없이 개발이 이루어질 경우 제대로 동작하는 시스템을 만들기 힘들다는 걸 실감하고 있다. 이런 고려에 대해 시스템 적인 배려가 너무 많지 않냐고 지적할 수 있겠지만, 아주 당연하지만 곧잘 잊고 있는 명제 하나로 답을 대신 하겠다.
‘우리가 만드는 모든 소프트웨어는 운영체제와 하드웨어 위에서 실행된다. 여기를 벗어나 작동할 수는 없다.’

댓글

이 블로그의 인기 게시물

[메모] PostgreSQL에서 Insert 하는 경우 자동채번 PK가 중복에러 나는 경우

[C# & LINQ] 랜덤으로 데이터를 한 개 추출하는 방법

[react-native] uuid 생성이 에러가 날 때 대처법