FE 전배
준비 & 적응 후기.
프론트엔드 개발, 이상진 😶
입사 : UI 개발
전배 : 프론트앤드 개발
- 블로그
- Selective
- 지식인
- 플레이스 (파견)
- A&B 테스팅 툴 (사내 Pasta 플랫폼)
- 자동차 보험
- 엔트리
- 현: 판매자 센터
2017.03
2020.03
Work Dialog.
- 인플루언서
1. 전배를 생각하게 된 계기
2. 준비 과정
3. 전배 후 1년
4. 후기 및 느낀 점
5. Q&A
Index.
1.
전배를 생각하게 된 계기
1. 새로운 작업 환경
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8902984/pasted-from-clipboard.png)
AS-IS
HTML/CSS DIFF 전달
FE와 분리된 환경
순수한 HTML/CSS 파일
FE 코드 이해 필요 x
![](https://media2.giphy.com/media/CaiVJuZGvR8HK/giphy.gif)
TO-BE
JSX 형식의 파일
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8846666/스크린샷_2021-08-17_오후_2.24.19.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8851292/markupGuideRND.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8851305/markupGuideRND_2.png)
UIT 리엑트 마크업 가이드 RND
AS-IS
HTML/CSS DIFF 전달
TO-BE
FE팀과 분리된 환경
순수한 HTML/CSS 파일
FE 코드 이해 필요 x
JSX 파일에 함께 작업
FE팀과 같은 저장소
FE 코드 이해 필요 o
import React from 'react';
import style from './TodoList.scss';
const DEMO_PROPS = {
itemList: [
{ id: 1, todo: '투두리스트 컴포넌트 실습 완성하기' },
{ id: 2, todo: '투두리스트 컴포넌트 실습 복습하기 ' },
{ id: 3, todo: '새로운 내용 공부하기' },
]
};
class TodoList extends React.Component {
render () {
const { itemList } = DEMO_PROPS;
return (
<ul className={style.list_todo}>
{itemList.map((item) => (
<li className={style.item_todo} key={item.id}>
<span className={style.text}>{item.todo}</span>
<button
type="button"
className={style.button_delete}
aria-label="삭제"
>
<i className={style.icon_delete} />
</button>
</li>
))}
</ul>
)
}
}
export default TodoList;
최초 작업 > 데모 데이터
import React from 'react';
import { useSelector } from "react-redux";
import { getTodos } from "../redux/selectors";
import { VISIBILITY_FILTERS } from "../constants";
import TodoItem from "./TodoItem";
import style from "./TodoList.scss";
const TodoList = () => {
const visibilityFilter = useSelector((state) => state.visibilityFilter);
const allTodos = useSelector(getTodos);
const itemList =
visibilityFilter === VISIBILITY_FILTERS.ALL
? allTodos
: visibilityFilter === VISIBILITY_FILTERS.COMPLETED
? allTodos.filter((todo) => todo.completed)
: allTodos.filter((todo) => !todo.completed);
if (itemList.length === 0) {
return <h2>등록된 Todo가 없습니다.</h2>;
}
return (
<ul className={style.list_todo}>
{itemList.map((todo) => {
return (
<TodoItem
key={`todoItem-${todo.id}`}
todo={todo}
/>
);
})}
</ul>
);
};
export default TodoList;
개발 완료 > 리얼 데이터 + 로직
FE 개발 이후
추가 작업
FE 작업의 일부분 수행하는 케이스
간단한 이벤트 구현
(ex: 툴팁, 팝업 Toggle)
const [isShowLayer, setIsShowLayer] = useState(false);
function handleClickCancel(e) {
setShowLayer(false)
}
...
return (
{isShowLayer && (
<TooltipLayer onClose={handleClickCancel} />
)}
)
상위 컴포넌트에 있는 리얼 데이터 적용
const ChildComponent = () => {
const DEMO_PROPS = {
name: 'jack',
id: 'ads21',
imgUrl: 'https://via.placeholder.com/728x90.png',
desc: 'dummy desc text!!'
}
const { name, id, imgUrl, desc } = DEMO_PROPS;
return (
<div>
<div>{name}</div>
<div>{id}</div>
<img src={imgUrl} />
<p>{desc}</p>
</div>
);
}
const ChildComponent = (data) => {
const { name, id, imgUrl, desc } = data;
return (
<div>
<div>{name}</div>
<div>{id}</div>
<img src={imgUrl} />
<p>{desc}</p>
</div>
);
}
After
Before
리얼 데이터 관련
코드 확인 필요한 경우
- 예상치 못한 데이터로 인해 UI 이슈 발생 / 기존 스펙 확인 필요
개발 코드 직접 확인
→ 커뮤니케이션 비용 발생
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8884662/스크린샷_2021-08-31_오후_8.51.57.png)
예시
import React from 'react'
import { Link } from 'react-router-dom';
const MovieItem = ({ data }) => {
const { id: movieId, name: movieName, platform, slug, poster } = data;
return (
<div className="movie-item" key={movieId}>
<Link to={`/detail/${platform}/${slug}`} className="movie-item__drop">
<img className="movie-item__img" src={poster} alt={movieName} loading="lazy"/>
</Link>
<div className="movie-item__name">{movieName}</div>
</div>
)
}
export default MovieItem;
MovieItem.jsx
import React from 'react'
import PropTypes from 'prop-types';
import { Link } from 'react-router-dom';
import MovieItem from './MovieItem';
import LoadingUI from './LoadingUI';
const movieList = ({ movies }) => {
const { movieList = [] } = movies;
return (
<div className="movie pt-5">
<div className="d-flex align-items-center justify-content-between mb-4">
<h2 className="">FİLMLER</h2>
<Link to="/add/movie" className="movie-add yellow">Film Ekle</Link>
</div>
{movieList?.length === 0 && <LoadingUI />}
<div className="row">
{movieList.map((movie, index) => (
<MovieItem
key={`movieItem${index}`}
data={movie}
/>
))}
</div>
</div>
)
}
movieList.propTypes = {
movies: PropTypes.object.isRequired
};
export default movieList;
MovieList.jsx
import React, { PureComponent } from "react";
import propTypes from "prop-types";
import { connect } from "react-redux";
import GameList from "../components/gameList.jsx";
import MovieList from "../components/movieList.jsx";
import { fetchMovies } from "../actions/movies";
import { clearDetail, fetchGames } from "../actions/games";
import { searchDisableOverlay } from "../actions/search";
class moviesPage extends PureComponent {
static propTypes = {
movies: propTypes.object.isRequired,
games: propTypes.object.isRequired,
};
render() {
return (
<div>
<div
className={`search-overlay ${this.props.boolSearchOverlay === "true" ? "active" : ""}`}
onClick={this.closeOverlay}
/>
<div className="custom-container product">
<GameList games={this.props.games} />
<MovieList movies={this.props.movies} />
</div>
</div>
);
}
componentDidMount() {
this.props.fetchMovies(); //action
this.props.fetchGames(); //action
this.props.clearDetail(); //action detay state temizle
}
componentWillUnmount(){
this.props.searchDisableOverlay();
}
closeOverlay = () => {
this.props.searchDisableOverlay();
}
}
const mapStateToProps = (state) => {
return {
movies: state.movies,
games: state.games,
boolSearchOverlay: state.search.searchOverlay
};
};
const mapDispatchToProps = {
fetchMovies,
fetchGames,
clearDetail,
searchDisableOverlay
};
export default connect(mapStateToProps, mapDispatchToProps)(moviesPage);
ProductPage.jsx
import React, { PureComponent } from "react";
import propTypes from "prop-types";
import { connect } from "react-redux";
import GameList from "../components/gameList.jsx";
import MovieList from "../components/movieList.jsx";
import { fetchMovies } from "../actions/movies";
import { clearDetail, fetchGames } from "../actions/games";
import { searchDisableOverlay } from "../actions/search";
class moviesPage extends PureComponent {
static propTypes = {
movies: propTypes.object.isRequired,
games: propTypes.object.isRequired,
};
render() {
return (
<div>
<div
className={`search-overlay ${this.props.boolSearchOverlay === "true" ? "active" : ""}`}
onClick={this.closeOverlay}
/>
<div className="custom-container product">
<GameList games={this.props.games} />
<MovieList movies={this.props.movies} />
</div>
</div>
);
}
componentDidMount() {
this.props.fetchMovies(); //action
this.props.fetchGames(); //action
this.props.clearDetail(); //action detay state temizle
}
componentWillUnmount(){
this.props.searchDisableOverlay();
}
closeOverlay = () => {
this.props.searchDisableOverlay();
}
}
const mapStateToProps = (state) => {
return {
movies: state.movies,
games: state.games,
boolSearchOverlay: state.search.searchOverlay
};
};
const mapDispatchToProps = {
fetchMovies,
fetchGames,
clearDetail,
searchDisableOverlay
};
export default connect(mapStateToProps, mapDispatchToProps)(moviesPage);
ProductPage.jsx
해당 데이터는 Redux 관련
→ 코드 읽기 위해선 학습 필요 📚
JSX 문법
/
React
/
Javascript
/
Redux
필요에 의한 학습
a. 모르는 부분 학습
b. 읽을 수 있는 코드 확장
c. 작업 범위 확장
[실무] + [필요] 에 의한 학습
FE 개발자로 일해보는건 어떨까? 🤔
→ 지루하지 않음, 마크업과 다른 종류의 즐거움
2.
전배 준비 과정 🔥
1. 호기로운 시작
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8884889/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8884893/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8884895/pasted-from-clipboard.png)
+
그 외 인터넷 강좌들
1. 호기로운 시작
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8903130/캡틴아메리카움짤.gif)
2. 좌절
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8893415/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8884883/완벽주의.png)
좁혀보자!
필요한 부분 부터
1. FE 개발자 로드맵
2. 전배 테스트
3. 토이 프로젝트
1. FE 개발자 로드맵
학습이 필요한 주제를 우선 순위에 맞추어
효율적인 "학습 순서"를 제시
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8893431/maze.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8885165/frontend__1_.png)
1. 구현 요건
2. 평가 기준 리스트 → 채점표
- 내 현재 실력 확인
- FE업무에 필요한 실무 능력 파악
- 학습 방향 설정 가능
2. 전배 테스트
출제되는 과제를 요구 조건에 맞춰 구현하는 방식
있으면 좋을 것 같은 웹서비스 구현
or
존재하고 있는 서비스 Clone 코딩으로 구현
3. 토이 프로젝트
🤖 토이 프로젝트란?
ex) 넷플릭스, 코로나 현황판
1. 구현 요건 정의(=기획서)
작업 전 해야 할 것
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8885249/스크린샷_2021-09-01_오전_12.45.09.png)
작업 전 해야 할 것
2. 기술 스택 정의
프레임워크 | 번들러 | 상태 관리 | 타입스크립트 | 테스팅 |
---|---|---|---|---|
Vue | webpack | Redux | O | Jest |
FE
프레임워크 | DB |
---|---|
Express | MySQL |
BE (optional)
작업 전 해야 할 것
3. 아키텍쳐 (mvc, mvvm, mvp 등)
프레임워크 없이 순수 JS (vailla JS)로 구현시
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8885278/mvc.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8885279/mvvm.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8885283/mvp.png)
mvc 패턴
mvvm 패턴
mvp 패턴
- Todo 리스트
- Todo + 캘린더
- Hackers News 클론 코딩
- 정렬 알고리즘 시각화
- 워드 클라우드
- 서점 서비스
- world news 서비스
- 위치기반 장소 예약 서비스
진행한 토이 프로젝트들
1. 정렬 알고리즘 시각화
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8893517/selectionSort.gif)
2. world news 서비스
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8893526/action_worldnews.gif)
📌 제가 생각하는 Tips
- 공부의 우선 순위를 정하기
- app 만들어보기 → 실무에 가까운 공부
- 자바스크립트
- 실무에 필요한 부분 찾아서 공부
- ES6 이상의 문법 권장
- 상태관리 & 비동기 처리
- 프레임워크, 라이브러리에 의존하지 않기
3.
전배, 그 후 1년
다양한 환경의 업무 경험
A/B 테스트 툴
2020.03
자동차 보험
엔트리
현: 판매자센터(스마트스토어/네이버 페이)
현: 판매자센터(스마트스토어/네이버 페이)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8894071/스크린샷_2021-09-03_오후_7.18.48.png)
A/B 테스팅 관리자 툴
신규 프로젝트
A/B 테스팅 관리자 툴
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900280/abtest.jpeg)
A 화면
B 화면
A/B 테스팅 관리자 툴
A 화면
B 화면
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900309/abtest_after.png)
기획, 디자이너 x
마크업 함께 진행 (UI 키트 이용)
특징
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900341/스크린샷_2021-09-06_오후_10.05.43.png)
Past UI Kit: https://pages.oss.navercorp.com/paas/ui-component
- 원하는 기술 스택 적용 가능
- 웹팩 설정 ~ 최종 빌드 산출물
→ 번들러, 개발 환경 구축 경험
→ 필요에 따라 자유롭게 기술 추가
특징 : 신규프로젝트
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900376/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900388/pasted-from-clipboard.png)
app_bundle.js
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900431/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900388/pasted-from-clipboard.png)
Context API
판매자 센터
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8894176/스크린샷_2021-09-03_오후_7.52.03.png)
기존 프로젝트 이관
→ 운영 / 유지 / 보수
특징
1. 최신 기술 스택, 고도화된 개발 환경
프레임워크 | 번들러 | GraphQL | 타입스크립트 |
---|---|---|---|
React+hook | webpack | O | O |
스토리북 | 테스트 프레임워크 | 스냅샷 테스트 | e2e 테스트 |
---|---|---|---|
O | Jest | O | O |
특징
2. 복잡한 인프라
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8894275/pasted-from-clipboard.png)
특징
3. 서비스 운영 & 배포
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900563/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900588/스크린샷_2021-09-06_오후_10.50.10.png)
4.
총평 및 느낀 점 🤔
느낀점 - 좋았던 점
1. Refresh
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900647/pasted-from-clipboard.png)
느낀점 - 좋았던 점
2. 다른 종류의 즐거움
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900675/html-css-js.gif)
느낀점 - 좋았던 점
3. UI 개발 경험은 큰 자산
- 마크업 관련 작업 혹은 이슈 처리
- 인터렉션, 애니메이션 작업
- HTML, CSS를 이용, 상대적으로 간단하게 개발 가능
의존성 감소 → 업무 시 이점
- 성능 최적화 작업
1. 넓어진 업무 범위, 높은 의존성
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900874/dia.png)
느낀점 - 힘든점
느낀점 - 힘든점
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900874/dia.png)
- 어려운 BackEnd 와 의사소통
- 여러 부서와 협업 필요
→ BE에 대한 학습이 필요
→ 가장 마지막에 작업
→ 일정 관리 어려움
1. 넓어진 업무 범위, 높은 의존성
2. 끝없는 학습의 필요성
느낀점 - 힘든점
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900897/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900898/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900899/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900431/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900906/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900908/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900910/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900918/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900376/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900924/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900925/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900926/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900928/pasted-from-clipboard.png)
- JS : Ecma, 다양한 프레임워크, 상태관리 lib
- 보조&인프라: Typescript, 스토리북, 테스팅
- 배포, 운영 : 람다, ncc, nelo 등
"필요할 때 공부하자"
느낀점 - 힘든점
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900897/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900898/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900899/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900431/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900906/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900908/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900910/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900918/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900376/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900924/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900925/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900926/pasted-from-clipboard.png)
![](https://s3.amazonaws.com/media-p.slid.es/uploads/744510/images/8900928/pasted-from-clipboard.png)
- BE : GraphQL, nodejs, http 통신 등
2. 끝없는 학습의 필요성
4.
Q&A
감사합니다 😊
FE 전배
By Sang Jin Lee
FE 전배
- 614