Kevin
@kevin
수강생
6,561
수강평
265
강의 평점
4.8
주력 언어 또는 기술 : Java, Spring Framework, RxJava, Reactor, Spring WebFlux
(주) 펜타시큐리티 백엔드 개발자로 활동(From 2015.07 To 2022.01)
(주)코드스테이츠(https://www.codestates.com)에서 Senior Educational Software Engineer(Backend)로 활동
(From 2022.03 To 2024.01.31)
- 프리랜서 개발자 및 강사로 활동(Since 2024.02)
- 저서
안녕하세요? Kevin이라고 합니다. ^^
인프런에서 이렇게 강사로서 여러분들을 만나게 되어서 너무 반갑습니다.
어떤 분야든 마찬가지겠지만 특히나 소프트웨어 개발자는 끊임없이 변화하는 트렌드에 뒤처지지 않도록 항상 자기 자신을 갈고 닦는것이 개발자로써 살아남는 유일한 방법이라고 생각하며 항상 배우는 자세로 즐겁게 소프트웨어 개발을 하고 있는 개발자 중 한 명입니다.
제가 가지고 있는 지식과 경험이 다른 분들에게 조금이나마 도움이 되기를 바라면서 인프런에서 강좌를 시작하였습니다.
앞으로 수강생분들에게 현실적으로 도움이 되는 다양한 강좌로 꾸준히 찾아뵙도록 하겠습니다. 감사합니다.
질문이나 의견은 언제든지 환영하니, 이메일(it.village.host@gmail.com)로 편하게 얘기해주세요.
강의
클립
전체 1로드맵
전체 1수강평
- [기초 1편] OpenClaw.AI 마스터 클래스: Gemini와 Docker로 만드는 나만의 자율형 AI 에이전트
- [Java 실무 프로젝트 입문편] 객체지향 사고력 훈련 - 미니 프로젝트 3종 실습
- Kevin의 알기 쉬운 Spring Reactive Web Applications: Reactor 1부
게시글
질문&답변
도커 오류발생
안녕하세요 정호님.질문주신 내용에 대한 답변을 드려보겠습니다. openclaw-gateway 설정은 지금 강의에서 안내드린 구조(demo/config, demo/workspace)랑 잘 맞게 작성해 주셨어요.말씀하신 “Docker Desktop Files 탭에서 접속이 됐다 안 됐다 한다”는 증상은, Mac용 Docker Desktop이 호스트 폴더를 마운트할 때 생기는 이슈일 가능성이 큽니다.현재 .env를 보면:OPENCLAW_CONFIG_DIR=./config OPENCLAW_WORKSPACE_DIR=./workspace이렇게 상대 경로로 되어 있습니다.이 자체는 “반드시 demo 폴더 안에서 docker compose up을 실행한다”는 전제에서는 괜찮은데,Mac에서는 다음 두 가지 때문에 문제가 생길 수 있어요.docker compose up을 실행한 위치가 demo 폴더가 아닐 때예를 들어 상위 폴더에서 docker compose up을 실행하면,Docker 기준 ./config, ./workspace는 다른 실제 위치를 가리키게 됩니다.이 경우, 컨테이너에 마운트된 경로가 계속 바뀌면서 Files 탭에서 폴더가 보였다 안 보였다 할 수 있습니다.demo 폴더 위치가 Docker Desktop의 File sharing 허용 범위 밖일 때Docker Desktop → Settings → Resources → File sharing에서demo 폴더가 위치한 상위 경로(예: /Users/계정명/Projects 등)가 공유 허용으로 등록되어 있지 않으면,./config, ./workspace 바인드 마운트가 실패할 수 있습니다.이 때도 Files 탭에서는 마치 접속이 불안정한 것처럼 보일 수 있습니다.그래서 아래 순서로 한 번 점검해 보시면 좋겠습니다:항상 demo 폴더 안에서만 실행하기cd /Users/내계정명/path/to/demo docker compose down docker compose up -d openclaw-gateway이렇게 하면 .env에 있는 ./config, ./workspace가 항상 demo/config, demo/workspace를 정확히 가리키게 됩니다.Docker Desktop File sharing 설정 확인 (Mac 전용)Docker Desktop → Settings → Resources → File sharing에서demo 폴더가 들어 있는 상위 경로(예: /Users/내계정명/Dev, /Users/내계정명/Documents 등)가 목록에 포함돼 있는지 확인해 주세요.없다면 추가 후 Apply & Restart를 눌러 Docker를 재시작합니다.Files 탭에서 보는 경로 확인컨테이너 내부 기준으로:/home/node/.openclaw → demo/config와 연결 (설정, 내부 workspace 등)/home/node/workspace → demo/workspace와 연결 (실제 강의에서 쓰는 작업 폴더)Files 탭에서 주로 /home/node/workspace 아래를 보시고,demo/workspace에 파일을 하나 만들어서 양쪽에서 같이 보이는지 확인해 주세요.이렇게 했을 때도 Files 탭 접속이 계속 들쭉날쭉하다면,Mac Docker Desktop 버전 문제나, iCloud/보안 소프트웨어 쪽 간섭 가능성도 있을텐데,docker-compose logs -f 명령으로 오류 메시지가 표시되는게 있는지 확인해보시고, 오류 메시지를 보여주시면 다시 한번 분석을 해보겠습니다. 해결 되시길 바랄게요!감사합니다!
- 0
- 3
- 106
질문&답변
예제
Sol님, 안녕하세요?노션 문서를 PDF 문서로 변환하는 과정에서 글자가 잘린것을 확인했습니다.PDF 문서를 업데이트 해놓겠습니다.우선 노션 문서의 링크 자체에 접근 가능하도록 해드릴테니, 아래 링크로 접속하셔서 문서 확인하시면 되겠습니다. Stream API 강의 자료 및 연습문제 링크 https://www.notion.so/section1-class03-Stream-API-e2177c8ca10e469bb80f145ad7a01a3a?source=copy_link불편을 드려서 죄송합니다!
- 0
- 2
- 46
질문&답변
자바 2탄 3탄 커리큘럼 문의
안녕하세요? 추석 연휴는 잘 보내셨나요? 답변이 좀 늦어서 죄송하고 좋은 질문 해 주셔서 감사합니다. ^^질문 주신 부분들에 대해서 제 의견을 잠깐 말씀 드릴게요. "강사님의 강의 철학과 같이 자바 기본 문법들을 배우고 다양한 예제를 단계별로 풀어보며 비로소 왜 이렇게 돌아가는지 메커니즘이 궁금할때 위에 딥한 강의를 찾아보는게 낫다고 생각이 듭니다"--> 프로그래밍 언어를 배울때 일반적으로 두 가지 방식의 학습 방법이 있다는건 잘 알고 계실거에요. 하나는 특정 프로그래밍 언어의 문법 및 사용법 위주의 강의나 책을 모두 완강 또는 완독하고 난 후에 다음 스텝을 밟는것. 또 하나는 일단 아주 최소한의 사용법만 익힌 뒤 간단한거라도 만들어 보면서 막히는 부분이 있으면 다시 책을 찾아보면서 막히는 부분을 해결하면서 앞으로 나아 가는 것.둘 중에 어떤게 더 낫다 그렇지 않다라고 말씀 드리긴 어렵겠지만(사람마다 자신에게 맞는 학습 방법이 다를테니까요) 제 경험상 후자 쪽이 흥미를 잃지 않고 성장하기가 더 쉬운 것 같았습니다.그래서 Java 관련 미니 프로젝트 강의를 만들고 있는 중이구요. 요즘엔 한국인들도 영어로 잘 말하는 분들이 많지만 제가 영어를 배울때만 해도 문법 위주로 영어를 배웠는데 결국 외국인들 만나서 말 한마디 못하고, 외국인이 말하는 내용을 알아 듣지도 못하는 그런 상태가 되어버렸는데요. ^^;프로그래밍 언어도 우리가 배우는 영어라는 언어를 배우는것과 꽤나 비슷한 것 같더라구요.기본 문법이나 고급 기법을 배워도 이걸 이용해서 아주 작은 애플리케이션이라도 만들어보지 않으면 이걸 왜 배우고 어디에 써먹을 수 있는지 깨닫기 어렵다는 사실은 프로그래밍을 배우는 많은 분들이 느끼는 고민이라고 생각합니다.영어로 자신 있게 말할 수 있다는건 Java로 내가 생각하는대로 구현을 할 수 있다는 말과 같은 것 같고, 영어를 잘 알아 듣는다는 건 다른 사람이 짠 코드(Chat GPT 같은 AI 포함)를 잘 이해할 수 있다는 말과 비슷한것 같아요.이런 이유때문에 제 강의 수강생 인원이 적긴하지만 나름 현실적으로 도움이 될만한 괜찮은 강의라고 생각하고 있습니다. ^^; "혹시나 이 소인의 의견을 긍정적으로 보시고 관련된 내용이 반영 된다면 제발 주니어 입장에서 자세한 설명과 쉬운거 부터 단계별로 다양한 문제로 부탁 드립니다"--> 1부 강의의 세 가지 애플리케이션을 다 만들어보셨는지는 모르겠지만 1부 강의에 나오는 애플리케이션만 만들어 보셔도 나중에 웹 애플리케이션을 만들 때 Java의 왠만한 문법들은 잘 사용을 하실거라고 생각해요. 결론은 1부 강의가 제일 쉬운 단계입니다. ^^; 그것보다 더 쉬운건 실무적으로는 도움이 안될 거 같아서 제외한 부분도 있습니다. ^^; 2부 같은 경우에는 이번달에 오픈 예정인데 굉장히 중요한 주제로 프로젝트를 진행할 예정이에요. 태경님 주변을 돌아보면 '주문'과 관련된 서비스가 굉장히 많다는걸 아실 수 있을텐데요. 예를 들면 배달 앱, 쇼핑몰, 오픈 마켓, 티켓 예매 등등 무수히 많은 서비스가 무언가를 주문하는 시스템이죠. 그래서 주문이라는 도메인을 활용해서 어떤 애플리케이션을 직접 만들어보는건 굉장히 중요하다고 생각합니다.참고로 2부 강의는 1부 강의보다는 조금 더 난이도가 있기때문에 1부에서 구현에 대한 기본기를 잘 쌓으신 다음에 수강하시는게 머리가 덜 아프지 않을까 하는 의견드립니다. ^^; 3부는 위에서 태경님께서 잠깐 언급하셨던 Thread를 어떻게 활용할 수 있는지 왜 사용하는지에 대한 부분이 포함된 애플리케이션을 만드는 강의를 2부 강의 오픈 후에 순차적으로 오픈할 예정이에요.JavaFX를 이용해서 UI가 있는 굉장히 재미있는 애플리케이션을 만들어 볼 예정입니다. "마지막으로 ㅇ..이러면 안되지만.. ㅎ..혹시 2, 3탄 ㄹ..론칭 할인 할인 쿠폰을 제공해주실 예정이 있으신가욥..?"--> 쿠폰 제공하는게 그리 어려운 일이 아니라서 가능할 것 같습니다. ㅎㅎ 참고로 오픈때는 할인된 가격으로 오픈을 할 예정이니 가격에 대한 부담은 크지 않을 것 같다는 생각이 드네요.ㅎ그리고 1부 강의보다 2부 강의는 오히려 조금 더 낮게 책정할 예정이에요. 강의 퀄리티가 낮아서가 아니라 Java 입문하시는 분들 입장에서 1부도 중요하지만 2부가 더 중요하다고 판단되어서 혹여나 부담되는 가격때문에 제 강의를 안듣는 케이스를 줄이고 싶은 바램이 있어서 그렇습니다.제가 유명한 강사가 아니다보니 가격이 너무 낮으면 오히려 강의 퀄리티 의심이 따를수는 있겠지만 그건 어쩔 수 없죠. 제 강의 들으신 분들이 잘 판단해 주셔서 좋은 강의라고 말씀해 주시길 바랄 뿐입니다. ㅎㅎ 질문해 주신 부분에 대한 답변이 잘 되었는지 모르겠네요.더 궁금한게 있으시면 언제든지 편하게 말씀해 주세요. 감사합니다~
- 0
- 1
- 60
질문&답변
깃허브 주소 오류
안녕하세요? 불편을 드려서 죄송합니다.'강의 소개 > 학습 자료' 섹션에 총 4개의 Github 링크가 있고, 확인해보니 모두 Public Repository로 잘 연결이 되는데 혹시 어떤 경로로 접속해보니 접속이 안되시는지 여쭤봐도 될까요?
- 0
- 3
- 81
질문&답변
window 예제 1번 request(n) * maxSize 부분을 잘 모르겠습니다.
안녕하세요? 제가 해외에 있어서 답변이 조금 늦어진 점 양해 부탁드리겠습니다. 지금쯤 주무시고 계실것 같은데 여긴 아침이라서 아침 먹고 바로 답변쓰고 있습니다. ^^; 궁금해 하시는 내용이 아마도 window()라는 operator를 어떤 상황에서 적절하게 사용할 수 있는지 라고 생각되어서 이 부분을 말씀드릴게요. 공식 문서에서도 설명이 되어 있지만 window() operator는 upstream의 데이터를 지정된 개수만큼 포함한 flux window로 쪼개어서 downstream에서 처리하도록 한다 라고 나와있습니다.flux window라는건 말 그대로 window라는 단위로 데이터가 포함되어 있는데 이 데이터들을 각각의 flux를 이용해서 개별적으로 처리할 수 있다라는건데요(개별적으로 처리할 수도 있고, List로 변환해서 한꺼번에 처리할 수도 있을테구요).다만, buffer(maxSize) 같은 경우에는 maxSize만큼 데이터를 쪼개서 버퍼에 담지만 Downstream으로 내려줄때 flux가 아닌 List 형태로 내려줍니다.flux로 내려주느냐 List로 내려주느냐는 확연한 차이점이 있습니다.flux를 전달받으면 flux에서 emit되는 개별 데이터를 처리하기 위해 다른 Operator 들을 이용해서 유연하게 처리할 수있고, 비동기적인 처리도 손쉽게 할 수 있기 때문에 buffer 보다 조금 더 상황에 맞는 유연한 처리가 가능하다라고 생각합니다. buffer()는 쪼개어서 List에 담긴 데이터들을 한 번에 모아서 일괄 처리하는데 중점을 둔 operator이기 때문에 window() operator보다는 좀 더 처리가 심플할테구요. 물론 buffer가 아니라 window operator를 이용해서 buffer처럼 데이터를 한번에 일괄 처리할 수도 있을텐데 이 경우에 비동기적으로 처리할 수 있기 때문에 효율성 측면에서 더 나을 수 있다고 생각합니다. 한마디로 buffer는 쪼개어진 데이터에 대한 단순 일괄 처리, window는 단순 일괄 처리 이상의 작업들(비동기 처리, 데이터의 복잡한 가공처리, 지연 처리 등)을 처리할 때 사용한다. 이렇게 생각하시면 될 것 같아요. 답변이 도움 되셨으면 좋겠네요.감사합니다! 좋은 꿈 꾸세요~
- 0
- 2
- 52
질문&답변
subscription signal 에 upstream 으로 이동하는 순서
안녕하세요. 좋은 질문 주셔서 감사드립니다.아래 링크를 보시면 Reactor에서 signal이 어떤 흐름으로 발생하는지 정리가 잘 되어 있는데, 한번 읽어보시면 도움이 되실 것 같아요.https://itvillage.tistory.com/entry/Reactor-Sequence%EC%97%90%EC%84%9C-%EB%B0%9C%EC%83%9D%ED%95%98%EB%8A%94-signal%EC%9D%98-%EC%A0%84%ED%8C%8C-%ED%9D%90%EB%A6%84일단 핵심만 간략하게 말씀드리면, Reactor의 Operator는 기본적으로으로 Operator 하나를 Operator 체인에 연결할 때 마다 내부적으로 subscribe()가 한번씩 발생되면서 Upstream 쪽으로 subscription이 전파되는 식으로 전파가 끝나면 데이터가 Downstream 쪽으로 emit 되는 형태로 동작을 하는데요.이 흐름에 맞춰서 Context의 동작도 발을 맞추는 거라고 생각을 합니다.그런데 어떤 Operator 들(특히 Thread 관련된)은 내부 동작이 꽤 복잡해서 위 아래로 왔다 갔다하는 흐름도 보입니다.아무튼 링크에 적힌 내용들 천천히 읽어보시면 도움되실 것 같습니다.감사합니다~
- 0
- 2
- 80
질문&답변
Webflux의 Non-Blocking 특성에 대해 문의 드립니다.
안녕하세요. Non-Blocking에 관해서 질문을 주셨는데요.WebFlux에서 Non-Blocking이라는 개념은,Java에서 쓰레드를 추가로 할당해서 동시성의 형태로 여러 요청을 번갈아 처리하는 구조라기보다는,요청을 처리하는 쓰레드(이벤트 루프)가 특정 작업에 묶이지 않고 자유롭게 움직일 수 있는 상태, 즉 Blocking 되지 않은 상태를 말합니다.즉, Reactor 체인에서 별도의 쓰레드를 사용하지 않아도, Reactor-Netty 서버는 각 요청을 처리하는 흐름이 Blocking되지 않으면 하나의 이벤트 루프 ㅆ레드로도 여러 요청을 빠르게 처리할 수 있습니다.하지만 만약 어떤 요청이 순차적으로만 처리되고, 다른 요청이 기다리는 현상이 발생한다면,그건 보통 요청 처리 로직에서 Blocking 연산이 있거나, CPU 연산이 오래 걸려서이벤트 루프가 다음 요청으로 넘어가지 못하고 쓰레드가 점유된 상태일 가능성이 큽니다.즉, WebFlux의 Non-Blocking은 쓰레드가 작업 도중 Blocking 되지 않게 만드는 처리 방식임을 이해하는 것이 중요하다고 생각합니다.아직 3부를 제작하지 않은 상태여서 Spring MVC와 Spring WebFlux를 비교하는 샘플 테스트에서는 클라이언트에서 단순 for문을 이용해서 요청 처리를 시뮬레이션 했는데요.만약에 실무적으로 쓰레드가 Blocking 되지 않는다 라는 사실을 확인하려면 여러 클라이언트가 동시 다발적으로 요청을 보내는 상황을 만들어야 하고, 서버측 WebFlux 애플리케이션에서도 DB 등의 I/O까지 Fully Non-Blocking하게 처리하는 상황을 만들어서 테스트 해야하는데, 말씀하신 코드를 지금 다 만들기에는 사실상 무리가 있어서 3부 강의 때 말씀드려야 할 것 같아요.이점 양해 부탁드리고, Non-Blocking의 의미는 쓰레드가 Blocking 되지 않게 하는것이지 우리가 알고 있는 멀티 쓰레드 작업 처리 방식처럼 동시에 요청을 처리하는것은 아니라는 사실은 꼭 기억을 해주시면 감사드리겠습니다.
- 1
- 3
- 194
질문&답변
Downstream Mono, Flux가 subscriber인가요?
안녕하세요? Downstream Flux, Mono에 대해서 질문을 주셨는데요.아래 간단한 코드를 예로 들면(Mono도 같은 원리라고 보시면 됩니다.)Flux .just(1, 2, 4) .filter(num -> num % 2 == 0) .subscribe(result -> System.out.println(result));just()는 일반적으로 최초로 데이터를 emit하기 때문에 생산자, Publisher, 발행자로 이해하면 됩니다.그런데 filter() 입장에서는 just()가 Upstream Flux가 되고, 반대로 just() 입장에서는 filter()가 Downstream Flux가 됩니다.이렇게 부르는 이유는 just()와 filter() 같은 Operator들이 리턴하는 리턴 타입이 Mono 또는 Flux이기 때문입니다.즉, filter() 입장에서는 윗쪽에 있는 just()가 리턴하는 Flux를 이용해서 다음 흐름을 이어가기 때문에 just()가 Upstream Flux가 되는 것입니다. 그리고 Subscriber는 내부적으로 좀 복잡한 과정을 거치는데 다 이해하실 필요는 없고, 일반적으로 .subscribe(...) 여기에서 ... 에 해당되는 람다 표현식이 Subscriber라고 이해하셔도 무방할 것 같습니다. 혹시 제 설명이 좀 어려우시다면 just()와 filter() 같은 Operator 내부로 들어가셔서 리턴 타입을 직접 눈으로 확인하시면 좋을 것 같아요. 감사합니다!
- 0
- 1
- 148
질문&답변
onErrorResume을 사용하지 않는 모든 경우 예외 발생 시, 시퀀스는 종료되나요?
안녕하세요. 주말이라서 답변이 좀 늦었네요.onErrorResume 같은 에러 처리를 위한 Operator를 사용하지 않으면 기본적으로 Sequence 내에서 에러가 발생하면 Subscriber에게 onError Signal 형태로 에러 정보가 Exception 형태로 전달됩니다. 다만, onErrorResume을 사용하지는 않지만 특정 상황에서 onErrorContinue Operator를 사용하거나 retry Operator를 사용하면 에러 발생 시점에 Sequence가 즉시 중단되지 않을 수는 있습니다.방금 말씀 드린 내용은 error handling 섹션에 있는 영상으로 확인하실 수 있습니다. AI 인턴이 답변 남겨두었듯이 doOnError 같은 Operator를 이용하면 에러를 직접적으로 핸들링하는건 아니지만 에러가 발생했을 때, 로그를 남긴다든지 하는 후속 작업을 통해 에러를 간접적으로 알려서 추후에 디버깅을 할 수 있습니다. 디버깅 관련해서는 1부 영상을 확인하시면 될 것 같습니다.감사합니다.
- 0
- 2
- 219
질문&답변
source.next와 source.emit의 차이에 대한 질문입니다.
안녕하세요? 어제 일찍 잠이 드는 바람에 답변이 좀 늦어졌네요. 양해 부탁드리겠습니다. ^^; 우선 아래 예제를 실행시켜 보시면 next() 호출 후에 onComplete signal이 발생하지 않기 때문에 Sequence가 종료 되지 않고 무한 대기 상태가 되는걸 확인하실 수가 있는데요. TestPublisher source = TestPublisher.create(); StepVerifier .create(source.flux()) .expectSubscription() .then(() -> source.next(2, 4, 6, 8, 10)) .expectNext(2, 4, 6, 8, 10) .expectComplete() .verify(); 말씀하셨던대로 TestPublisherTestExample01에서 expectComplete()이 통과하는 이유는 zipWith()를 사용했기 때문입니다. 아래 그림을 보시면 zipWith()의 파라미터로 전달한 Flux에서 데이터 emit이 끝나면 onComplete signal이 발생하는데 zipWith()의 경우 둘 중 하나의 Sequenc가 종료될 경우 최종적으로 합쳐진 Source Flux에서 onComplete signal이 발생합니다.(사진)
- 0
- 2
- 204
블로그
전체 6![[리액티브 프로그래밍 에피소드] RxJava의 groupBy 연산자 추가 설명](https://cdn.inflearn.com/public/files/pages/7f6a338e-dcea-4761-b4bc-afd8d1a461db/K-008.png?w=260)
2021. 01. 21.
4
[리액티브 프로그래밍 에피소드] RxJava의 groupBy 연산자 추가 설명
안녕하세요? RxJava 강의를 진행하고 있는 Kevin입니다. 1부 강의를 수강하시던 수강생분의 질문 및 의견 사항이 있어서 다른 수강생분들에게 알리고자 블로그에 글을 남기게 되었습니다. 'Kevin의 알기 쉬운 RxJava 1부' 강의의 섹션 4 > 변환 연산자(2) 수업에서 groupBy를 설명하는 예제 코드가 있는데요. 그 중에서 두번째 예제 코드에 사용된 filter 연산자는 groupBy 연산자를 사용하면서 조금 쉬운 예를 보여드리려고 사용을 했지만 사실은 불필요하게 사용된 부분이 있습니다. 또한 groupBy 연산자의 진짜 사용 목적을 이해하기에 기존의 예제코드는 조금 부족한면이 있어서 groupBy 연산자 사용에 좀 더 적절한 예제 코드를 추가로 올려두었습니다. github에 올려둔 소스 코드를 잠깐 설명 드리자면, ==== ObservableGroupByExample03 === /** * 제조사를 그룹으로 묶어서 자동차 명을 출력하는 예제 */public class ObservableGroupByExample02 { public static void main(String[] args) { Observable, Car>> observable = Observable.fromIterable(SampleData.carList) .groupBy(Car::getCarMaker); observable .flatMapSingle(carGroup -> carGroup.flatMap(car -> Observable.just(car.getCarName())) .toList() ) .subscribe(System.out::println); }} : 제조사별로 자동차 명만 출력하는 예제입니다. groupBy( ) 연산자는 Observable을 반환을 하는데 이 GrouppedObservable을 flatMapSingle( ) 연산자를 이용해서 해당 그룹별로 통지되는 Car 객체 중에 CarName만 얻은 후,(CarName을 얻기 위해서 내부적으로 flatMap() 연산자를 한번 더 사용했음) toList()를 통해 Single로 CarName이 담긴 list를 통지하는데요. 여기서 flatMapSingle( ) 연산자는 Observable 이렇게 Observable이 이중으로 감싸져 있는 부분에서 바깥쪽 Observable을 한꺼풀 벗겨내고 GroupedObservable로 평탄화 시켜주는 역할을 합니다. flat이란 의미 자체가 평평하게 해준다는 그런의미가 있으니 이 의미를 기억하시면 될 것 같습니다. flatMap( )과 달리 flatMapSingle( ) 연산자는 새로운 Observable로 데이터를 여러번 emit 하는게 아니라 연산자 이름에서와 같이 Single Observable로 단 한번만 emit을 한다는 사실 역시 기억을 해두시구요. flatMapSingle( ) 연산자 내부에 있는 flatMap( ) 연산자는 Observable에서 바깥쪽에 감싸져 있는 Observable을 벗겨내고 Car 객체로 평탄화 시켜주며, 이를 통해서 Car Name을 얻을 수 있고, toList( ) 연산자를 사용해서 Single로 한번만 emit 되게 됩니다. 출력 결과는 아래와 같습니다. ===================================== [티볼리, G4렉스턴] [SM6, SM5] [말리부, 트래버스, 트랙스] [쏘렌토, 팰리세이드] 그리고 네번째 예제 코드를 하나 더 추가했습니다. ==== ObservableGroupByExample04 ==== /** * 제조사 별로 그룹으로 묶은 후, 제조사 별 차량 가격의 합계를 구하는 예제 */public class ObservableGroupByExample03 { public static void main(String[] args) { Observable, Car>> observable = Observable.fromIterable(SampleData.carList) .groupBy(car -> car.getCarMaker()); observable .flatMapSingle(carGroup -> Single.just(carGroup.getKey()) .zipWith( carGroup.flatMap(car -> Observable.just(car.getCarPrice())) .reduce((p1, p2)-> p1 + p2) .toSingle() , (key, sum) -> key + ": " + sum ) ) .subscribe(System.out::println); }} : 제조사 별 차량 가격의 합계를 구하는 예제인데요. 위의 ObservableGroupByExample03 코드와 거의 같은데 다른점은 제조사 별 차량 가격의 합계를 구하기 위해 reduce( ) 연산자를 한번 더 사용했다는 건데요. 조금 복잡해 보이지만 flatMapSingle( ) 내부를 잠깐 설명 드리자면, 차량 가격 합계 앞에 제조사를 표시해주기 위해서 zipWith( ) 연산자를 추가적으로 사용을했는데 .zipWith( ) 연산자는 zipWith( )연산자를 호출한 Observable source와 zipWith( ) 의 파라미터로 입력된 Observable source를 결합시켜서 가공된 데이터를 반환하는 연산자인데요. 위 코드에서 보시면, flatMapSingle( ) 내부의 Single.just(carGroup.getKey())의 Single과 zipWith( ) 의 파라미터로 입력된 Single(마지막에 toSingle( )이 붙어서 Single로 변환 됨)을 결합해서 새로운 데이터, 여기서는 key + ": " + sum 을 반환합니다. reduce( ) 연산자는 파라미터로 입력된 데이터 두개씩 누적하여 더해서 최종 결과로 하나의 데이터만 반환하기 때문에 Observable.just(1개 데이터)로 호출할 수 있고, 이를 다시 toSingle( ) 연산자를 사용해서 Single 로 변환될 수 있는것입니다. 출력 결과는 아래와 같습니다. ================================ CHEVROLET: 91000000 HYUNDAE: 61000000 SSANGYOUNG: 66000000 SAMSUNG: 75000000 좋은 지적을 해주신 윤지상님께 감사드리고, 다른 의견 있으시면 언제든지 문의 주세요. 감사합니다.
![[리액티브 프로그래밍 에피소드] Hello Reactor 들여다 보기](https://cdn.inflearn.com/public/files/pages/71e0624f-1799-4791-a193-fef327be86de/octavian-dan-iY6QMkP66mI-unsplash.jpg?w=260)
2021. 01. 21.
4
[리액티브 프로그래밍 에피소드] Hello Reactor 들여다 보기
안녕하세요? [Kevin의 알기 쉬운 RxJava] 강의를 진행하고 있는 Kevin입니다. 이번 시간에는 'Hello, Reactor' 코드를 가지고 Reactor의 기본 구조를 들여다보는 시간을 가져보겠습니다. 개발에 처음 입문하실때 대부분 'Hello World!' 코드를 실행해보셨을텐데요. Reactor 역시 마찬가지로 'Hello, Reactor' 메시지를 출력해보면서 Reactor의 기본 구조를 간단하게 살펴보도록 하겠습니다. 어렵지 않으니 가벼운 마음으로 글을 읽어주시면 감사드리겠습니다.^^ 먼저 아래의 코드를 보시죠. [Hello Reactor 코드] 여러분들이 아시다 시피 Reactor는 RxJava와 마찬가지로 Reactive Streams라는 표준 사양을 구현한 구현체입니다. 따라서 Reactive Streams에서 정의하고 있는 생산자 즉, Publisher와 소비자 즉, Subscriber를 구현하고 있는데요. 위의 코드에서 보시는것처럼 Reactor에서는 Flux가 대표적인 생산자 중에 하나입니다.위의 코드에서 소비자라고 되어 있는 부분은 람다 베이스 Subscriber가 되겠습니다. 생산자 쪽에서는 just라는 Operator(연산자)를 사용해서 두 개의 데이터를 소비자 쪽으로 통지를 하는데요. Reactor에서는 생산자 쪽에서 통지할 데이터를 정의하는 과정 자체를 묶어서 'Sequence(시퀀스)'라고 합니다. 이 Sequence라는 용어는 Reactor를 접하다보면 자주 나오는 용어이니 기억을 해두시길 바래볼게요. 생산자 쪽에서 소비자 쪽으로 데이터를 통지하는것이 맞긴하지만 최종 소비자까지 데이터가 전달 되기까지는 중간에 여러 Operator를 만날 수 있기때문에 엄밀히 말하자면 생산자가 소비자에게 데이터를 통지한다라고 말하기보다는 생산자가 Downstream으로 데이터를 내보낸다라는 표현이 더 정확할 것 같네요. 용어에 대한 부분은 아래쪽에서 다시 정의를 해보도록 하구요. 아무튼 생산자 쪽에서 데이터를 통지하게 되면 최종 소비자 쪽에 바로 데이터가 전달되는 것이 아니라 map( )이라는 Operator에서 원본 데이터가 가공 처리 된 후에 최종 소비자 쪽으로 전달이 되는것을 볼 수 있는데요. 여기서는 통지된 String 데이터를 소문자로 변환을 한 후에 최종 소비자쪽으로 전달하고 있네요. 자, RxJava 강의 시간에도 말씀을 드렸지만 리액티브 프로그래밍은 크게 세가지의 step으로 이루어져있습니다. 1 step : 생산자가 데이터를 통지한다.2 step : 통지된 데이터를 Operator로 가공한다.3 step : 가공 처리된 데이터를 최종 소비자에게 전달한다. 이 세가지 큰 흐름은 기본적으로 꼭 기억을 해두시고, 나머지는 데이터를 통지하는 다양한 방법, 데이터를 가공하는 다양한 방법, 비동기 프로그래밍을 위한 쓰레드를 할당하는 방법, 에러 처리 방법 등을 단계적으로 적용 하는 식으로 학습을 진행해 나가면 리액티브 프로그래밍을 조금 더 수월하게 이해하실 수 있을거라는 생각이 드네요. ^^; 자, 그럼 마지막으로 Reactor에 대한 에피소드를 계속 진행가기 전에 Reactor에서 사용되는 여러가지 용어를 정의하고 에피소드를 마무리 하도록 하겠습니다. 먼저 아래 용어들을 보시죠. Publisher : 발행자, 게시자, 생산자, 방출자(Emitter) Subscriber : 구독자, 소비자 Emit : Publisher가 데이터를 내보내는 것(방출하다. 내보내다. 통지하다.) Sequence : Publisher가 emit하는 데이터의 연속적인 흐름. 스트림과 같은 의미라고 보면 됨 Subscribe : Subscriber가 Sequence를 구독하는 것 Dispose : Suscriber가 Sequence 구독을 해지 하는 것 Downstream : 현재 Operator 체인의 위치에서 봤을때 데이터가 전달 되는 하위 Operator 및 method 체인 Upstream : 현재 Operator 체인의 위치에서 봤을때 상위 Operator 및 method 체인 여태껏 제가 데이터를 통지하는 쪽은 생산자로 지칭했는데요. 보시는대로 생산자 이외에 발행자, 게시자, 방출자 등 다양하게 사용이 되고 있습니다. 모두 같은 의미라고 보시면 되겠지만 앞으로 에피소드를 진행할 때는 그냥 영어로 Publisher라고 지칭하도록 하겠습니다. ^^; 따라서 소비자 역시 영어로 Subscriber라고 지칭하면 되겠구요. 데이터를 통지하는 행위 역시 영어 그대로 Emit 한다라고 하겠습니다. Sequence는 위에서 잠깐 말씀 드렸죠? Publisher쪽에서 데이터를 emit하는 흐름 자체를 통칭하는 것을 의미하는데, 예를 들어서 Flux라는 Publisher가 데이터의 Emit을 정의하는 부분을 설명할때 Sequence를 생성한다 라고 표현할 수 있겠습니다. Subscribe와 Dispose는 구독하다, 구독을 해지하다라고 표현하도록 하겠습니다. 마지막으로 Downstream과 Upstream이라는 용어인데요. Reactor를 학습하다보면 종종 나오는 용어인데 개념적으로 이해하기 모호한 면이 있는 용어중에 하나이기도 합니다. 이럴때는 그냥 단순하게 이해를 하는게 제일 좋을거라고 생각을 해보게되네요. ^^;예를 들어 위의 코드에서 just( )의 위치에서 Downstream은 map( )부터 subscribe( )까지 하위 체인이 되겠습니다. 그리고 subscribe( ) 입장에서는 map( )과 just( )가 Upstream이 되겠구요. just( )의 내부를 들여다보면 return 값으로 Flux를 반환하는데요. just( )에서 반환하는 Flux를 원본 Flux가 되겠습니다. 그리고 map( )에서 반환하는 return 값 역시 Flux인데요. 여기서의 Flux는 원본 Flux가 아닌 가공 처리된 데이터를 가지고 있는 새로운 Flux입니다. Flux(또는 Mono)의 이러한 처리 흐름때문에 Downstream이나 Upstream이라는 용어가 생겨난것 같은데 위에서 언급드린것처럼 단순하게 생각해주시면 될것 같아요. 자, 오늘은 'Hello, Reactor' 코드를 통해서 Reactor 의 기본 구조를 살펴보았는데요. 다음 시간에 다른 에피소드를 가지고 다시 찾아뵙도록 하겠습니다. ^^ 감사합니다!
![[리액티브 프로그래밍 에피소드] 이벤트 루프란?](https://cdn.inflearn.com/public/files/pages/8089d213-3273-4fd1-a642-d0dd63c0f555/kinson-leung-ctG084PsBs8-unsplash.jpg?w=260)
2021. 01. 21.
5
[리액티브 프로그래밍 에피소드] 이벤트 루프란?
수강생 여러분 안녕하세요. RxJava 강의를 진행하고있는 Kevin입니다. 오늘은 리액티브 프로그래밍과 밀접한 관련이 있는 이벤트 루프에대해서 잠시 알아보도록하겠습니다. 이벤트 루프에 대해서 먼저 이야기 하기 전에 저희는 서블릿에 대한 언급을 먼저 하고 넘어가야되는데, 그 이유는 이벤트 루프라는 개념이 나오게 된 배경에는 서블릿이 있기때문이에요. 그럼 서블릿에 대한 이야기를 먼저 해볼까요? 서블릿의 기본 개념 서블릿은 뭘까요? 자바를 사용하는 개발자이거나 자바를 배우고 계신 분들이 웹 애플리케이션을 만들어 보셨다면 이미 서블릿을 사용해보셨을겁니다. 여러분들이 JSP를 사용해보셨거나 아니면 Spring framework을 사용해보셨다면 여러분들은 알게 모르게 서블릿이란 놈을 사용해보셨다는 말씀. ^^ 서블릿은 웹에서 클라이언트의 요청을 동적으로 처리하기 위해 서블릿 규약이라는 일정한 규칙에 맞춰서 작성되는 클래스인데요. 이 클래스들이 클라이언트로 부터 들어오는 요청을 받아서 응답으로 되돌려주는 역할을 하죠. 개발자가 작성한 서블릿 클래스가 HttpServlet을 상속 받고, doGet( ), doPost()를 구현하는 것이 서블릿 클래스의 기본이라는 사실은 서블릿 클래스를 사용해보신분들은 너무나 잘 알고들 계실겁니다. Spring에서의 서블릿 어쨌든 저희가 HttpServlet 같은 상위 클래스를 상속 받아서 개발을 진행할건 아니기때문에 서블릿에 대해서 더 자세한 이야기를 할 필요는 없을 것을 같네요. 다만, 이것 하나만은 기억을 하셔야 될 것 같습니다. Spring MVC 역시 내부적으로는 Servlet 기술을 사용을 한다는것을요. DispatcherServlet 이라는 녀석을 기억하시죠? Spring MVC에서는 이 DispatchServlet이라는 녀석이 최앞단에서 클라이언트의 요청을 전달 받아서 해당 요청에 매핑되는 Controller 에게 요청을 전달한다는 사실은 Spring MVC로 개발을 해보신분들은 잘 알고 계실겁니다. 서블릿 방식의 문제점 그런데 이러한 서블릿을 사용하여 클라이언트의 요청을 처리하는 방식에는 큰 문제점이 하나 있는데요. 서블릿 방식은 클라이언트에서 요청이 들어오면 해당 요청을 처리하기 위해서 요청 당 쓰레드 하나씩을 생성해서 처리합니다. 하나의 쓰레드에서 클라이언트의 요청을 다 처리하면 이 쓰레드는 쓰레드풀이라는 쓰레드의 저장소에 다시 반납이 되는데, 참고로 이 쓰레드 풀은 톰캣 같은 서블릿 컨테이너가 관리를 해줍니다. 사실 클라이언트의 요청이 폭주만 하지 않으면 지금과 같은 서블릿 방식이 큰 문제가 되지는 않겠지만 클라이언트의 요청이 쓰레드의 갯수에 비해 기하급수적으로 늘어나는 순간 문제가 시작됩니다. 요청을 처리하기 위한 쓰레드가 쓰레드 풀에 남아있지 않을 경우 기존에 사용되던 쓰레드가 쓰레드 풀에 다시 반납이 되어 다른 요청을 처리하기 위해서 재사용할 수 있 때까지 클라이언트로 부터 들어온 요청들은 대기를 해야되니까요. 이런 성능상의 문제점을 상당 부분 해소할 수 있는 방식이 바로 이벤트 루프 방식인데요. 그럼 이벤트 루프 방식이 무엇인지, 어떻게 클라이언트의 요청을 효과적으로 처리하는지 간단하게 살펴볼까요? 이벤트 루프란 아래 그림을 보면서 이벤트 루프에 대해서 설명 드리겠습니다. 클라이언트가 서버로 요청을 보내면 요청 핸들러가 클라이언트의 요청이 들어왔다는 이벤트를 이벤트 루프에 푸시합니다. 이벤트 루프는 그림과 같이 계속해서 루프를 돌면서(한마디로 무한루프) 요청 핸들러로부터 푸시된 이벤트를 감지합니다. 그리고 나서 해당 이벤트에 대한 콜백을 등록한 후, 클라이언트가 요청한 작업을 처리합니다. 작업이 끝나면 작업이 끝났다는 이벤트를 이벤트 루프에 푸시하고 등록된 콜백을 호출한 후, 요청 핸들러를 다시 거쳐서 클라이언트에게 최종적으로 응답을 되돌려줍니다. 어떠신가요? 이벤트 루프가 무엇인지 대충 감이 오시는지 모르겠네요. 이벤트 루프 방식의 장점은 쓰레드 하나로 굉장히 많은 요청을 병렬로 처리하기때문에 기존의 서블릿 방식의 성능상의 문제를 해결한다는것입니다. WebFlux와 이벤트 루프 Spring WebFlux가 바로 이벤트 루프 방식을 사용하기때문에 대량의 클라이언트 요청을 효과적으로 처리할 수 가 있게되었는데요. Spring WebFlux를 사용해서 대량의 클라이언트 요청을 효과적으로 처리하는 애플리케이션을 한번 만들어보고 싶어지지 않으셨나요? ^^; Spring MVC냐 Spring WebFlux냐 자, 그러면 무조건적으로 Spring MVC 대신에 Spring WebFlux를 사용하면 좋은것이냐하면 사실 그건 아닌것같습니다. Spring MVC로 개발을 진행해보셨다면 아시겠지만 생산성이 대단하다는것을 느끼실 수가 있을겁니다. 그리고 RxJava 2부 강의에서 비동기 방식의 디버깅에 대한 이야기를 드리겠지만 비동기 방식보다는 동기 방식이 디버깅도 용이하고 여태껏 사용해온 익숙한 명령형 프로그래밍 방식으로 코드를 짜면 되니 코드를 짜는 부담 역시 줄어드는게 사실일테구요. 하지만 분명한것은 사물 인터넷, 자동차, 인공 지능 등등 우리가 생각하는 전통적인 클라이언트 이외에 다양한 클라이언트들이 계속해서 생겨날텐데 이런 종류의 클라이언트들이 계속해서 생겨나면 생겨날수록 서버가 감당해야 되는 요청의 수는 점점 늘어나겠죠. 마이크로 서비스로 인해서 또한 서비스들 간의 요청도 점점 늘어나고 있기도 하구요. 결론은 지금 당장은 아니더라도 개발자로서 미래를 준비하고 싶으신 분은 리액티브 프로그래밍 기법을 꼭 익혀두셨으면 하는 바램입니다. ^^ 이야기는 길었는데 결론은 꽤 간단하다는.. ^^;; 오늘은 이벤트 루프에 대한 이야기를 간단하게 해보았는데요. Spring WebFlux에 대한 이야기로 또 찾아뵙도록 할게요. 감사합니다~
![[리액티브 프로그래밍 에피소드] 리액터와 WebFlux](https://cdn.inflearn.com/public/files/pages/a1abffe4-2140-4825-bbb0-210981335b10/reactor.png?w=260)
2021. 01. 21.
8
[리액티브 프로그래밍 에피소드] 리액터와 WebFlux
RxJava 강의를 수강하시는 수강생 여러분 안녕하세요? 강의를 진행하고 있는 Kevin이라고 합니다. 지난번 공지에서 잠깐 말씀을 드렸다시피 매주 한두번 정도 시간을 내서 강의에서 제대로 얘기하지 못했던 리액티브 프로그래밍에 대한 뒷 얘기들을 조금씩 해볼까 합니다. 리액티브 프로그래밍을 배우고자 하시는 분들께 조금이나마 더 도움이 되길 바래보겠습니다. 리액터(Reactor)란 무엇일까요? 리액티브 프로그래밍에 대해서 처음 들으시는 분들은 리액터에 대해서 당연히 모르실거 같은데 아마도 스프링을 학습하면서 들어 보신분도 있지 않을까하는 생각도 들긴하네요. ^^ 예상하신분도 계시겠지만 리액터는 Java로 구현 된 리액티브 프로그래밍의 한 종류입니다. 더 정확히 얘길 하자면 Reactive Streams를 구현한 구현체라고 볼 수 있는데요. 강의를 수강하신 분들은 이미 알고 계시지만 RxJava 역시 Reactive Streams를 구현한 구현체의 하나라고 볼 수 있습니다. 일반적으로 Reactive Streams를 구현한 구현체들은 대부분 Rx~로 시작을 하는데 Reactor는 그것보다 더 확실하게 "나는 리액티브 프로그래밍을 사랑하는 Reactor야" 라고 얘길 하는것 같군요.^^ Reactor라는 이름에서 리액티브 프로그래밍의 느낌이 팍팍 오지 않으신가요?ㅎ 리액터(Reactor)를 배워야 할까 말아야 할까 결론부터 말씀드리자면 리액티브 프로그래밍을 배우기로 하셨다면 리액터는 배우는것이 맞다고 생각합니다. 두가지 이유만 얘길 드리자면 먼저 리액터를 통해서 저희는 명령형 프로그래밍의 한계를 넘어설 수 있는 그리고 시대에 맞는 개발 패러다임을 이해하고 실무에 점차적으로 사용을 하게 될 것입니다. 끊임없이 생산되는 데이터를 효과적인 비동기 상태로 처리할 수 있어야 한다는 사실은 필연적이라는 생각이 드니까요. 그렇기 때문에 Reactor는 꼭 학습을 하시는게 좋을 것이라는 생각이 드네요. 굳이 왜 리액터일까? 근데 왜 굳이 리액터를 배워야 되는가.. 라고 생각을 하실수도 있겠네요.^^; 저희는 지금 RxJava를 배우고 있는데 말이죠. 음.. Java 애플리케이션을 개발해보신 분들은 아시겠지만 Java 애플리케이션을 개발하면서 Spring Framework을 빼놓고 얘기하는게 어려워진 것은 오래되었습니다. 물론 Spring을 사용하지 않고, 애플리케이션을 만들 수는 있지만 Spring을 일단 한 번 사용하게되면 Spring 없이 개발하겠다고 얘기하는 분들은 많지 않을거 같아요. Spring 얘기를 왜 하느냐하면 Reactor가 바로 Spring5에서 지원하는 Reactive 프로그래밍의 기본이 되기 때문인데요. Spring을 사용하시는 분들, 그리고 앞으로 Spring을 접하실 분들이라면 Spring과 궁합이 딱 맞는 Reactor를 배우지 않을 이유가 있을까 싶습니다. Spring과 Reactor를 사용해서 Spring MVC 기반의 애플리케이션 대신에 리액티브 애플리케이션을 만들어보는것. 재미있을 것 같지 않나요? ^^ 그럼 RxJava는 배우지 말라는거? 그건 당연히 아닙니다. 제가 RxJava 강의를 오픈한 가장 큰 이유 중에 한 가지는 RxJava라는 기술 자체 보다는 리액티브 프로그래밍에 대해서 알려드리고 싶어서이기 때문인데요. 리액티브 프로그래밍은 처음 접하게 되면 이해하기가 쉽지 않기때문에 리액티브 프로그래밍에 대한 기본 개념을 잡을 수 있도록 하는것이 제 강의의 가장 큰 목표라고 볼 수 있습니다. 그런 의미에서 제 강의는 다른 의미로 여러분들한테 충분히 의미있는 강의가 될거라고 믿어보겠습니다.^^ 제 강의를 듣고 Reactor를 접하게 된 후에 생각했던 것보다 Reactor가 어렵지 않구나라는 얘기를 꼭 들었으면 좋겠네요. ^^ Reactor는 이제 알겠는데 WebFlux는 뭐지? 저희 강의를 조금이라도 수강을 하신 분들은 알고 계실텐데요. RxJava에서 데이터를 통지(또는 발행, 방출)하는 생산자의 역할을 하는 놈이 Observable, Flowable, Single, Maybe 등인데, Reactor에서 이러한 역할을 하는 놈이 바로 Flux와 Mono라는 놈입니다. RxJava에서는 데이터를 한 건만 통지할 때에는 Single을 사용하고, 데이터를 한 건도 통지하지 않거나 한 건만 통지할 때는 Maybe를 사용 하죠. 그리고 데이터를 한 건 이상 통지할 때에는 Observable 또는 Flowable을 사용을 합니다. 뭔가 좀 복잡하죠? Reactor에서는 이걸 조금 단순화해서 Mono라는 놈은 딱 한 건의 데이터만 처리하고, Flux는 한건도 통지하지않거나 한건 이상 통지하는데 사용을 하도록했습니다. Flux에 대해서 말씀을 드렸으니 WebFlux는 무얼하는 놈인지 대충 감이 오시죠?'혹시 Web에서 사용하는 Flux?' 맞습니다.^^ Spring MVC가 웹 계층에 특화된 웹프레임워크인 것과 마찬가지로 WebFlux는 웹 계층에서 비동기 처리를 하는데 특화된 리액티브 프로그래밍 기반의 웹 프레임워크라고 할 수 있습니다. 그러니까 우리는 WebFlux라는 저놈을 Spring MVC 처럼 효과적으로 잘 사용 하기 위해서 Reactor를 먼저 배우게 되는 것입니다. 구체적으로 어떻게 사용하는지는 아직 자세히 모르더라도 WebFlux가 대충 뭐하는 놈인지는 대충 이해가 되시죠? 그러면 Reactor의 Flux를 사용하는 코드 예시를 조금 살펴보고 오늘 이야기를 마무리 하도록할게요. 먼저 RxJava에서 사용하는 코드부터 간단하게 살펴보겠습니다. @Testpublic void ObservableFilterTest() { Observable observable = Observable .just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) .filter(n -> n % 2 == 0); observable.test() .assertValues(2, 4, 6, 8, 10) .assertComplete();} RxJava 2부 강의에서 만나보시겠지만 Observable에서 통지하는 데이터들에 대한 Unit Test 코드입니다. Observable의 just() 함수를 사용해서 1부터 10까지 10개의 데이터를 통지하면 filter() 함수에서 통지된 데이터를 2로 나눈 나머지가 0인 숫자 즉, 짝수인 숫자만 필터링을 해서 최종적으로 소비자 쪽에 통지를 하는 간단한 코드인데요. 이렇게 통지된 데이터가 정상적으로 소비자 쪽에 전달이 되는지 검증하기 위해서 Observable의 test() 함수를 이용해서 검증을 합니다. 자, 그러면 이번에는 Reactor에서 사용하는 코드를 한번 보실까요? @Testpublic void fluxFilterTest() { Flux flux = Flux .just(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) .filter(n -> n % 2 == 0); StepVerifier.create(flux) .expectNext(2, 4, 6, 8, 10) .verifyComplete();} Flux의 just()함수를 사용해서 1부터 10까지 10개의 데이터를 통지하면 filter()함수에서 역시 짝수인 숫자만 필터링을 해서 소비자 쪽에 통지를 합니다. 그러면 StepVerifier 클래스를 이용해서 소비자 쪽에 전달되는 데이터를 검증을 하고 있습니다. RxJava와 거의 똑같다는거 느껴지시죠? 그렇기때문에 여러분들은 저희 강의를 통해서 리액티브 프로그래밍의 기본 개념을 확실하게 자기 것으로 만든 후에 Reactor의 코드를 보면 '아.. 어렵지 않네?'라고 말씀하실수 있을거라고 생각합니다. ^^ 그럼 저는 다음 시간에 리액티브 프로그래밍의 또 다른 에피소드를 가지고 다시 뵙도록 할게요. 감사합니다!

2021. 01. 21.
5
비전공자가 개발자로 입문하고 성장하기 위한 방법 조언
안녕하세요, Kevin입니다. 새벽에 아기가 깨서 다시 재웠는데 잠이 안와서 이렇게 몇자 적게되었네요. 인프런에 Java 개발자 로드맵을 오픈한지 1년 6개월이 넘은거 같은데 매일 매일 지속적으로 수강 신청을 해주시는거 보면서 개발자가 되고자 하시는분들이 참 많구나 라는걸 새삼 느끼게 되는데요. 한편으로는 개발자 되는 길이 너무 막막해서 어디서부터 시작해야될지 몰라서 헤매었던 과거의 제 모습이 문득 생각이 나더라구요. 처음 접하는 용어와 프로그래밍 문법들이 많이 어려웠었고, 전체적인 개념을 잡는게 너무 어려웠던게 사실이니까요. 아무튼 지난 일들을 생각해보면 저 역시도 개발자가 되기 위해서 순탄한 길을 걷지 못했구나 라는 그런 생각이 듭니다.ㅎ 아무튼 개발자로서 입문 하기 위한 현실적인 방법에 대해서 잘 나와 있는 글들이 있어서 새벽에 잠깐 소개 드릴게요. - 소프트웨어 개발자가 되기 어려운 이유: https://www.techm.kr/news/articleView.html?idxno=2137- 개발 배우기가 정말 어려운 이유: https://brunch.co.kr/@jypthemiracle/14 글들을 보시면 아시겠지만 비전공자가 개발자로 입문하는것은 정말 쉬운일이 아니라는 생각이 드네요. 저처럼말이죠. 하지만 절대 넘을 수 없는 벽도 아니고, 일단 입문을 하게되면 해볼만하단 것과 실제로 너무 재미있다는 얘기 또한 드리고싶습니다. 그러니 이왕 시작하기로 마음 먹으셨다면 절대 포기하지 마시고, 열심히 노력하셔서 꼭 원하시는 개발자의 세계로 입문 하실 수 있길 멀리서나마 기원 드려봅니다. 질문이 있으시면 언제든지 성심 성의껏 답변 드릴테니까 편하게 해주시면 감사드리겠습니다. 그럼 저는 또 시간내어 찾아뵐게요. 감사합니다.

2021. 01. 20.
10
자신에게 맞는 회사 찾기(for Java Developer)
수강생 여러분 안녕하세요? 코로나 확산으로 인해서 생활하시는데 어려움이 많으시죠? 다들 건강하게 목표로 하시는 일들 잘 이루시길 바래 보겠습니다. 오늘은 개발자로서 처음 사회에 발을 디디시는 분, 그리고 개발 경력이 아직은 짧은 분들에게 입사 또는 이직을 위해 어떤 기업을 선택하는것이 좋을지 제가 경험한 내용을 토대로 얘기를 드려볼까해요. 각자의 생각과 의견이 모두 다른만큼 제가 말씀드리는 이야기는 기업을 선택하시는데 있어서 참고만 할 수 있는 용도가 되길 바래보겠습니다. 저희 강의가 자바 개발자 로드맵이니 자바 개발자 위주로 얘길 드리겠습니다. 자바 개발자가 되는 것은 과연 괜찮은 선택일까? 저희 나라에는 현실적으로 자바 개발자의 수요는 많은 편입니다. 많은 기업들이 백엔드의 서버 애플리케이션으로 자바 기반의 애플리케이션을 사용하고 있기때문에 자바 개발자의 수요는 여전히 적은편은 아니라고 생각합니다. 안드로이드 앱 개발은 두말 할 나위도 없을테구요. 자바를 먼저 배울까 파이썬을 먼저 배울까 그리고, 요즘 처음 개발에 입문하시는 분들은 배우기 쉽고, 직관적인 파이썬으로 많이들 입문하시는데 제가 처음 개발에 입문할 때와 마찬가지로 현재까지도 개발 입문 언어로 자바를 많이들 선택을 하는걸로 알고 있습니다. 어떤 언어를 선택하느냐는 전적으로 개인의 선택이겠지만 시장의 수요를 잘 고려하셔서 선택을 하셔야 될 것 같은데, 파이썬의 Django나 Flask 등을 사용해서 웹 애플리케이션 개발을 하기도하지만 최근에는 데이터 과학(인공지능 개발 포함) 분야에서 파이썬이 인기를 끌고 있는게 사실입니다. 저도 데이터 과학 쪽에 관심이 많고, 미래를 준비하기위해서 시간을 쪼개서 파이썬을 학습하고 있는 중이기도합니다. 처음부터 데이터 과학 분야의 길로 가시고 싶다면 자바보다는 파이썬을 먼저 배우는게 당연히 낫겠죠? 그리고 처음 프로그래밍에 입문 할 때 역시 배우기 쉬운 파이썬이 적합하다라고 합니다. 하지만 채용 시장의 수요를 생각하면 자바는 필수이지 않을까라고 생각해보게되네요. 강의에서도 말씀 드렸지만 자바 개발자가 되기 위해서는 어떤 것들을 알아야되고 배워야 하는지에 대한 구체적인 내용은 나중에 다시 얘기를 드리겠구요. 오늘은 순전히 자바 개발자로서 자신에게 맞는 기업을 잘 선택하기 위한 기준과 기업 유형에 대해서 주로 얘기를 해볼까 합니다. 내 성향에 맞는 기업은 어떤 기업일까? 그럼 자신에게 맞는 기업이라는 것의 기준은 무얼까요? 우선 첫번째로 자신의 성향을 스스로 잘 파악하고 있어야 될 것 같습니다. 최근에는 기업의 조직문화가 과거의 수직 구조에서 수평적인 구조로 바뀌는 경우가 점점 많아 지고 있는데요. 개인적인 생각으로는 우리 나라 기업의 수직 구조는 군대 문화가 많은 영향을 끼친것 같다는 생각이 듭니다. ㅡ.ㅡ 아무튼 그런 딱딱한 수직 구조에서 부드러운 수평 구조로 바뀌어 가고 있는 추세인건 틀림없다라는 생각이 들긴하는데, 특히나 그런 경향은 스타트업 기업의 경우에 더 두드러지는것 같습니다. 수평 문화의 대표적인 특징은? 수평 문화가 자리 잡은 기업에는 직급이라는게 없는 기업이 많고, 누구누구 님~ 이렇게 부르면서 직급을 신경쓰지 않고 동료 간에 자유롭게 자기 의견을 주고 받는 경우가 많습니다. 어떤 기업들은 한국 이름 대신에 영어 이름을 사용해서 조금 더 수평적인 관계를 유지하려고도 하구요. 나는 수직? 아니면 수평적인 성향? 자, 그러면 여기서 자신이 수직적인 문화가 잘 맞는지 수평적인 문화가 잘 맞는지 곰곰이 한번 생각을 해보는것도 자신에게 맞는 기업을 선택하는 방법중에 하나라고 볼 수 있겠습니다. ^^; 예를 들면, 저 역시도 수평적인 문화가 단점보다는 장점이 더 많다라고 생각은하지만 수평적 문화에 낯설어하시는 분들도 꽤 있으신거 같더라구요. 수평적인 문화가 정착이 된 기업 같은 경우에는 멤버들간에 직급이나 나이에 크게 신경을 쓰지 않고, 오직 서로가 팀에 속한 팀원이라고 생각하고 업무를 진행하는 경우가 대부분이니 그런 조직 문화가 어색하거나 어색해서 개선을 해야되는데 도저히 개선이 되지 않는다면 수평적인 문화가 본인한테 맞지 않을 가능성이 높을거라고 생각합니다. 나에게 맞는 기업 유형은? 다음으로 자신이 어떤 업무 타입의 기업에서 일을 하고 싶은지에 대해서 고민을 해볼 필요가 있습니다. 자바 개발자로서 일을 할 수 있는 기업의 유형은 크게 시스템 통합, 웹 에이전시, 자체 소프트웨어 또는 서비스 제공 기업으로 나눌 수 있을 것 같습니다. 시스템 통합 기업의 특징 시스템 통합은 System Integration, 흔히들 말하는 SI 기업입니다. SI 기업은 주로 고객(금융권, 공공 기업, 학교 등의 단체)의 의뢰를 통해 해당 고객의 요구사항에 맞춰서 고객이 요구하는 시스템을 만들어 주는데요. 저희 나라에서는 시스템 통합을 위한 개발을 고객사에 직접 파견을 나가서 수행을 하게 되는 경우가 많습니다. 작게는 10명 미만 많게는 수백명으로 구성된 프로젝트 매니저, 설계자, 개발자들이 짧게는 수개월 길게는 1년 이상의 프로젝트 기간동안 함께 시스템을 구축 합니다. 요즘은 어떤지 모르겠지만 일단 대체적으로 야근이 많은 편입니다. 야근이 많은 이유는 여러가지 복합적인 이유가 존재하겠지만 SI 프로젝트 자체가 고객의 요구사항을 직접적으로 반영해야되는 구조이고, 기간내에 프로젝트를 끝내지 못하면 지체 상환금을 지불해야되는 구조도 많다보니 일단 프로젝트 기간이 정해지면 그 기간안에 끝내기 위해서 야근을 많이 하는 그런 구조인 경우가 많은것 같은데 아마도 모든 SI 기업이 그렇지는 않을거라고 생각하지만 아무튼 그러한 경향이 많다는 사실은 여러분들도 알고 계셔야할것 같네요. 웹 에이전시 다음으로 웹 에이전시가 있는데요. 웹 에이전시는 과거에는 주로 기업, 공공기관 등의 웹 사이트를 제작하는 비중이 높았었는데 최근에는 웹 에이전시 기업에서도 시스템 통합처럼 규모가 있는 프로젝트를 진행하는 경우도 많은데요. 제가 웹 에이전시에서 근무한적은 없지만 친한 지인이 웹 에이전시에서 근무하면서 규모있는 프로젝트를 진행하는것을 보았더랬습니다. 웹에이전시에서는 과거에는 PHP를 상당히 많이 사용했었는데 요즘은 어떤지 모르겠네요. JSP를 아직도 사용하고 있는 기업도 더러 있는것 같던데 제대로 된 애플리케이션을 개발하기 위해서는 JSP 기술 자체만을 사용하는 것은 지양되고 있다는 사실을 기억해두시면 좋겠습니다. 참고로 고객에 대한 컨설팅 업무도 SI 기업이나 웹 에이전시 기업에서 병행한다는 사실도 추가로 말씀드릴 수 있겠네요. 자체 소프웨어 또는 서비스 제공 기업 세번째로 얘기 드릴 수 있는 기업은 자체 소프트웨어나 서비스를 제공하는 기업을 들 수 있겠는데요. 자체 소프트웨어를 판매하는 대표적인 기업 유형은 보안을 전문으로 하는 기업을 들 수 있겠습니다. IT 보안 전문회사에서는 주로 바이러스 백신, DRM 솔루션, 암호화 솔루션, 웹 방화벽 등의 제품을 기업이나 공공기관에 납품을 하고 관리를 해주게되는데요. 온라인 서비스를 제공하는 경우도 있겠지만 고객사에 방문해서 고객 시스템에 자사의 보안 솔루션을 설치하고 구성을 해주는 경우가 많습니다. 그렇기때문에 보안 회사의 경우에는 보안 솔루션 자체를 깊게 연구하고 개발하는 연구원들이 따로 있고, 실제로 고객사에 자사의 보안 솔루션을 설치, 구성, 설치 후 지원을 해주는 기술 지원팀이 추가로 구성이 되어 있는 경우가 많은데요. 개발자들을 고객사에 파견해서 프로젝트를 진행하는 SI 기업과는 약간 성격이 다르지만 종종 기술 지원이 끝날때까지 고객사에 짧은 기간 동안 상주를 하는 경우도 있다는 사실을 기억해두시면 좋을 것 같네요. 설치형 소프트웨어가 아닌 서비스를 제공해주는 기업들도 많죠? 기업 이름을 일일이 열거하기가 좀 그렇지만 여러분들도 많이들 알고 계시는 대형 게임 회사들, 포털 사이트, 온라인 전자 상거래 기업 등의 서비스 제공 기업은 상당히 많은게 사실입니다. 이러한 서비스 제공 기업들은 대부분의 서비스를 온라인으로 제공을 하기 때문에 파견 근무가 거의 없다고 볼 수 있구요. 이런 서비스 제공 기업들은 더 좋은 서비스를 만들기위한 고민을 많이 하기때문에 기술 트렌드에 관심을 가지는 기업들이 많습니다. 물론 기술 트렌드만 쫓아간다고해서 좋은 서비스를 제공하는건 아니지만 발전하는 기술을 분석하고 자사의 서비스를 더 좋은 서비스로 개선하기 위한 노력들을 끊임없이 하는것이라고 보시면 될것같네요. 여러분들은 어떤 유형의 기업에서 일하고 싶으신가요? 자, 오늘은 세가지 정도 유형의 기업들에 대한 얘기를 해보았는데요. 어떠신가요? 여러분들에게 맞는 유형의 기업은 어떤 기업일까요? 저는 다른건 제쳐두고 제가 지금보다 더 성장할 수 있고, 더 발전할 수 있을 것 같은 느낌이 드는 그런 기업이 매번 더 끌리는건 변하지 않는것 같습니다. ^^; 아무튼 조금은 두서없이 얘기를 드렸는지도 모르지만 개발자로 사회에 입문하시는 분들 또는 사회에 발을 디디신지 얼마 되지 않은 분들이 자신에게 맞는 기업을 잘 선택하시는데 조금이나마 도움이 되시길 바래보겠습니다. 코로나 시대가 다가온것이 안타까운건 저 또한 마찬가지이지만 다른 한편으로는 개발자의 길을 걸어 가시려는 분들께 개발자가 되는것이 지금보다 충분히 더 가치가 있다라는 사실도 덩달아서 보여주는것 같습니다. 모두들 건강 관리 잘 하시고, 그럼 저는 다음에 또 다른 이야기로 찾아뵐게요. 감사합니다.








