일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- activeElement
- 자바스
- Purdue university
- 사파리 가상키보드
- 모던 자바스크립트 Deep Dive
- 퍼듀대학교
- 리액트 가상키보드
- 자바스크립트 렉시컬스코프
- React Query
- 모두의시간
- active blur
- 자바스크립트 변수 호이스팅
- touchmove 이벤트
- 자바스크립트 옵셔널 체이닝
- refetchOnWindowFocus
- 자바스크립트 스코프 체인
- but requested an insecure XMLHttpRequest endpoint 'http://~~’. This request has been blocked; the content must be served over HTTPS.
- 자바스크립트 논리합 연산자
- ios 크로스브라우징
- 로현 청춘의개발
- 자바스크립트 호이스팅
- EC2 HTTPS로 연결
- 자바스크립트
- 자바스크립트 null 병합
- K-SW SQUARE
- Kafka
- net::R_SSL_PROTOCOL_ERROR
- AWS 로드밸런서
- 자바스크립트 중첩함수
- 리액트 쿼리
- Today
- Total
개발 여행자, 현
[인턴활동] NHN Cloud 2개월간의 여정 본문
NHN에서의 2개월

1. 회사지원
한국에 돌아가면 개인 프로젝트 진행하면서 CS와 알고리즘 공부를 하려고 했는데 학교 홈페이지에서 NHN의 채용공고를 보게 되었다.
미국에서 한창 프로젝트를 진행하고 있는 도중이었고 LA에 있는 일정이었기에 지원기간이 정말 촉박했다.
밤 새고 LA에서 돌아온 당일 급하게 지원서를 작성했고 급하게 지원버튼을 클릭했다.
채용공고에 플랫폼 개발팀이라고만 적혀있고 정확한 기술스택이 기재되어있지 않았다.
구글링을 통해 알아낸 결과 플랫폼 개발은 주로 자바와 Vue.js를 사용하는 부서라는 사실을 알게되었고 자신감이 급하락했다.
평소 리액트, 리액트네이티브를 이용해서만 개발을 해보았지 자바와 Vue는 거의 무지하다고 보면 되었다.
그래도 배우면 되겠지! 하는 마음에 무작정 서류합격 전에 면접을 준비했다.
2. 서류합격
기간이 꽤 지났는데 연락이 오지않아서 떨어진줄 알고 잠시 면접은 내려놓고 미국 프로젝트에 집중했다.
새벽에 숙소 공용공간에서 개발을 하고있는 도중에 띠링- 하는 소리와 함께 합격 메일을 전달받았다.

기쁨반 걱정반.. 기술면접은 한 번도 준비해본 적이 없던 탓에 걱정이 정말 많았다.
복수전공을 조금 더 일찍 시작해서 다양한 전공을 들을걸.. 하는 후회와 함께 프로젝트는 잠시 내려놓고 면접 준비를 시작했다.
3. T면접
면접은 한국시간 오후 2시에 진행되었다
NHN에서는 기술면접을 T면접이라고 하는데 오로지 기술과 관련된 질문만 진행된다고 하여 걱정이 정말 많았다.
나는 일자가 촉박해서 그동안 진행했던 프로젝트를 세세하게 정리하고 CS 전공기초 위주로 준비했다.
면접은 2:3으로 진행이 되었고 예상과는 다르게 기술보다 인성면접에 초점이 맞춰졌 있었다.
물론 기술 관련 질문도 중간중간 있었지만 면접관분들이 정말 편하게 대해주셔서 편안한 기분으로 자신감 있게 얘기할 수 있었다.
미국 시간으로 새벽 1시였기에 비몽사몽 하기도 했지만 얼굴이 빨개질 정도로 최선을 다했던 기억이 새록하다.
제대로 답하지 못한 질문들도 있었고 정반대로 답한 질문도 있었기에 면접이 끝난 이후 사실 별 기대를 하지 않았다.
좋은 경험이었다라는 생각이 들었고, 미국 프로젝트에 집중했다.

그래도 사실 사람인지라 기대를 안한 건 아니었고, 결과 발표 날 새벽에 뜬 눈으로 지새웠는데 결과는 합격이었다 (우와!)
4. 프로젝트

프로젝트는 실무가 아닌, 인턴 개인별로 미니 프로젝트를 진행했다.
저는 검색 관련 플랫폼 부서에 배치가 되었고, 실제 서비스에서 사용되는 기술스택들을 적용하여 서비스의 한 기능을 클론코딩 했다.
프로젝트를 진행할 때 정한 목표는 다음과 같았다.
- 서비스 개발의 전체적인 흐름을 이해
- 개발자로서의 성장에 도움이 되는 실무에서 주로 사용하는 기술 사용
- 빅데이터와 클라우드 기술과 관련된 프로젝트 지향
- Java/Springboot를 이용해 웹 클라이언트와 백엔드 사이의 소통 방식을 이해
기술스택

기술스택은 다음과 같이 선정했고, 부서에서 사용하는 기술스택들을 최대한 적용하려 했다.
kafka, elsaticsearch, logstash와 같이 처음 들어보는 기술들이 정말 많았는데, 덕분에 실무에서 어떠한 기술들이 주로 쓰이고 구축이 되는지 알 수 있는 중요한 시간이었다.
아키텍처

로그생성 및 로그검색 웹
: 백엔드단에서 처리한 로그 데이터를 시각화 하기위해 리액트를 이용하여 웹페이지를 제작한다.
[기술스택]
React, TypeScript, Styled Component, recoil
[기능]
- 로그생성 기능
- 로그검색 기능
- 페이지네이션
[전체 페이지 화면]

1) 로그생성 기능

: 임의로 더미 로그데이터를 생성하기 위한 기능
: Project Version(필수값), Project Name(필수값), Log Version(필수값), Body Length(랜덤하게 들어갈 Body 문자열의 길이), Number(로그생성 개수)
[기능설명]
- 로그생성 메뉴를 클릭하면 입력할 수 있는 input 창이 표시된다.
- 로그를 생성할 때는 중복 생성을 방지하고자 로딩스패너를 두어 클릭 이벤트를 막는다.
- 필수값이 빈값으로 들어오지 않으면 로그 생성을 막는다.
- Body Length와 Number가 number 타입으로 들어오지 않으면 로그의 생성을 막는다.
[코드 중 일부 설명]
- 데이터 형식
POST/
kafka/object
logData =
{
"projectVersion": projectVersion,
"projectName": projectName,
"logVersion": logVersion,
"body": randomBody,
"count": count
};
const makeLog = useCallback(async () => {
try {
setIsMakeLoading(true); // 로그를 생성하고 있을 때 state값을 true로 변경하여 로딩스패너 컴포넌트를 띄운다.
while (count < logNumber) { // 사용자가 입력한 생성할 로그의 수만큼 반복문을 돌며 로그를 생성한다.
const chracters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz1234567890"; // 랜덤 문자열을 위한 상수값
let randomBody = "";
for (let i = 0; i < bodyLength; i++) {
randomBody += chracters.charAt(
Math.floor(Math.random() * chracters.length)
);
}
const logData = {
projectVersion: projectVersion,
projectName: projectName,
logVersion: logVersion,
body: randomBody,
count: count
};
count++;
const response = await axios.post("[http://localhost:8080/kafka/object](http://localhost:8080/kafka/object)", logData);
}
setIsMakeLoading(false);
alert(`${logNumber}개의 로그를 생성하였습니다.`);
} catch (e) {
console.error("error", e);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [logNumber, projectVersion, projectName, logVersion, bodyLength]);
2) 로그검색 기능
: ElasticSearch에 적재되어 있는 로그데이터를 검색하기 위한 기능

프로젝트를 진행할 때 elasticSearch에 적재된 데이터들을 최대한 백엔드단에서 전처리 하고자 노력했다.
처음에는 프론트엔드단에서 정제되어 있지 않은 데이터를 처리했는데 불필요한 리소스라고 판단했다.
searchLog() (수정전)
: Scroll API(무한 스크롤) 기능으로 구현을 하고, 백엔드 단에서 데이터를 전처리 하지 않고 프론트 단에서 데이터를 처리하도록 구현했던 코드이다.
[코드 중 일부 설명]
: elasticSearch/projectName에 GET API를 요청하여 response 값을 받는다
: 받아온 response 값에서 필요한 값만을 추출하여 result 변수에 저장한다.
: logData state 값을 변경시켜, 리렌더링이 되도록 하고 화면에 데이터를 그려준다.
const searchLog = useCallback(async () => {
console.log('projectNameSearch:', projectNameSearch)
try {
const response = await axios.get("http://localhost:8080/elasticSearch/projectName", {
params: {
projectName: projectNameSearch
}
});
var result : object[] = [];
for (var i = 0; i < response.data.data.length; i++){
const scrollData = response.data.data[i].hits.hits.map((data: any) => ({
projectName: data.sourceAsMap.projectName,
projectVersion: data.sourceAsMap.projectVersion,
logVersion: data.sourceAsMap.logVersion,
body: data.sourceAsMap.body
}))
result.push(scrollData);
}
setLogViewData(result);
} catch (e) {
console.error("error", e);
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [projectNameSearch]);
searchLog() (수정후)
-> Search API / Search After API를 사용하고 백엔드 단에서 데이터를 전처리 하는 방향으로 수정했다.
[코드설명]
: elasticSearch/projectName에 GET API를 요청하여 response 값을 받는다
: 받아온 response 값에서 필요한 값만을 추출하여 result 변수에 저장한다.
: 이전 방법과는 다르게 백엔드 단에서 데이터를 전처리해서 보내주므로, 프론트단 State값에 response 값을 그대로 저장한다.
const searchLog = useCallback(async () => {
try {
setIsSearchLoading(true); // 로그 검색을 시작했을 때 state 값을 변경하여 로딩스패너를 띄워 클릭을 막는다.
const response = await axios.get("[http://localhost:8080/elasticSearch/projectName](http://localhost:8080/elasticSearch/projectName)", {
params: {
projectName: projectNameSearch,
pageNumber: pageNumber,
pageSize: pageSize
}
});
setIsSearchLoading(false)
setLogViewData(response.data.dataObjects);
setTotalValue(Number(response.data.totalValue));
setIsTableVisible(true); // 로그를 불러오고 데이터 저장이 완료되면 isTableVisible state값을 변경하여 테이블을 띄운다.
} catch (e) {
alert("데이터를 찾을 수 없습니다.");
console.error("error", e);
}
}, [pageNumber, pageSize, projectNameSearch]);
전체적인 코드는 보안상 공개를 할 수 없지만, 관련 학습했던 내용들은 '백엔드' 카테고리에 기록했습니다.
백엔드 카테고리
[Table 관련 레퍼런스]
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/table
https://developer.mozilla.org/en-US/docs/Web/CSS/table-layout
https://code-masterjung.tistory.com/82
5. 겪은 어려움 및 배운점
프로젝트를 진행하면서 겪었던 어려움은 다음과 같았다.
- Java/Sprinboot를 처음 사용해보았기에 짧은 기한내에 수행하는데에 어려움이 있었다.
- Kafka, Elasticsearch 등과 같은 빅데이터와 관련된 기술을 사용하면서 설정값을 Default 값으로만 설정했다는데에 아쉬움이 있었다.
- 보안상 로컬에서만 테스트를 할 수 있었습니다. 실제 클라우드 서비스를 사용해보지 못했다는 것이 아쉬워 이후 개인적으로 AWS 기술을 사용해보기도 했다.
- 프론트단에서 오류를 사전에 막는 동시에 백엔드단에서도 오류 분기처리를 진행하지 못했다는데에 아쉬움이 있었다.
- Kakfa에서 오류가 발생했을 때 생성한 로그가 손실되는 문제가 있었다.
프로젝트를 진행하면서 배우고 느낀점은 다음과 같습니다.
- 웹 클라이언트와 백엔드단이 서로 어떻게 소통을 하는지 알게 되었다.
- REST API 를 작성하는 법을 알았다
- 개발공부를 할 때 결과에 초점이 맞춰지는 것이 아니라 과정에 초점을 맞추는 것이 중요하다는 것을 깨달았다.
- Kafka와 Elastci search의 구동원리에 대해 알았다.
- 백엔드단은 클라이언트와의 API 소통 뿐만 아니라 서버, 메모리 등 고려해야 할 점이 많다는 것을 알았다.
- 클라이언트와 서버 사이의 CORS 에러가 왜 발생하는지, 어떻게 해결하는 지 알았다.
- 여러 개발자들과 소통을 하고 회의에 참여하면서 어떻게 커뮤니케이션을 해야하고 의사결정을 내려야하는지 알았다. 또한 꾸준한 학습의 중요성을 다시금 깨달았다.

NHN Cloud에서 인턴을 하며 모든 게 새로운 기술들이어서 힘들고 어려운 점도 많았지만, 이를 통해 성장하고 배운 점이 훨씬 많았다.
이때 느끼고 배운 모든 감정과 생각들을 잊지않고 최선을 다해 더 나은 개발자로 성장해보자!!!