2주차 후기

삼성 청년 SW 아카데미를 다니면서 도전했던 2번의 B형, Professional 시험 중 한 번은 합격 가능성이 있었던,, 아까운 기억이 있다.
그 때 문제가 아마 그래프 축소 + 다익스트라였던 것으로 기억하는데 아쉽게 다익스트라 알고리즘을 몰라 BFS로 선회, 불합격했었다.


그 이후로도 다익스트라, 프림, 크루스칼 알고리즘 등이 내 발목을 계속 잡길래 학습의 필요성을 느꼈어서,
이번 코드트리 조별과제 이벤트에 참여해 학습해보고 있는데 코드트리 이거,, 참 물건이다.
알고리즘을 학습하면서 가장 불편하고 어려웠던 부분이 동일 알고리즘의 다른 유형 문제를 찾는 것이었는데 코드트리를 쓰면 그런 문제를 안 찾아도 된다는게 정말 편해서 취직 전까지는 사용할 것 같다. 개인적으로 결제할 의향 O


다익스트라 관련 개념과 문제 풀이를 진행 중이다. 정리한 내용을 일부 공유하면

정의 : 시작점부터 모든 정점으로 가는 최단거리를 구하는 알고리즘. 음수 가중치가 없어야 한다
시간 복잡도 : O(ElogV) = 인접 리스트, O(V^2) = 인접 행렬

 


이 정도는 알고 있었는데, 아래 내용이 참 좋다.

모든 정점으로부터 특정 도착점
특정 시작점에서 특정 도착점
사전순으로 가장 앞선 최단거리


위와 같은 유형에 대해 다익스트라를 어떻게 활용할 것인가? 에 대한 고민을 하게 되는 계기였달까..
아직 다익스트라와 어사지만 점점 친해지는 중이다.

문제 풀이

https://www.codetree.ai/missions/8/problems/shortest-path-to-each-vertex-3?&utm_source=clipboard&utm_medium=text

 

코드트리 | 코딩테스트 준비를 위한 알고리즘 정석

국가대표가 만든 코딩 공부의 가이드북 코딩 왕초보부터 꿈의 직장 코테 합격까지, 국가대표가 엄선한 커리큘럼으로 준비해보세요.

www.codetree.ai


위 문제는 다익스트라의 가장 기본형 문제로 단순히 한 정점에서 다른 모든 정점으로 가는 최소값을 구하면 되는 문제이다.
인접 리스트를 이용한 풀이. 간단하니까 코드만 놓고 가겠다.

#include <iostream>
#include <vector>
#include <limits>
#include <queue>
using namespace std;

void getInput();
void initData();

int N, M;
priority_queue<int, vector<int>, greater<int>> pq;
vector<vector<vector<int>>> edges;
vector<int> dists;


const int MAX_VALUE = numeric_limits<int>::max();

int main() {
    getInput();
    initData();

    while(!pq.empty()) {
        int s = pq.top();
        pq.pop();

        for (int i = 0; i < edges[s].size(); i++) {
            vector<int> tmp = edges[s][i];
            int next = tmp[0], value = tmp[1];
            
            if (dists[s] + value < dists[next]) {
                dists[next] = dists[s] + value;
                pq.push(next);
            }
        }
    }


    for (int i = 1; i < N; i++) {
        if (dists[i] == MAX_VALUE) cout << -1 << "\n";
        else cout << dists[i] << "\n";
    }
    
    return 0;
}

void initData() {
    dists.resize(N);
    for (int i = 0; i < N; i++) 
        dists[i] = MAX_VALUE;

    dists[0] = 0;
    pq.push(0);
    
    return;
}

void getInput() {
    cin >> N >> M;
    edges.resize(N);

    int start, end, value;
    for (int i = 0; i < M; i++) {
        cin >> start >> end >> value;
        edges[start - 1].push_back({end - 1, value});
    }

    return;
}

일년이 마무리되기까지 21일이 남았네요.

항상 그렇듯, 목표했던 일은 생각처럼 잘 이루어지지 않고 아쉬운 점이 많은 한 해였습니다.

한 해의 성과와 아쉬움을 기억에만 담고 있으면 점점 잊혀져가니 이를 한 번 정리해보도록 합시다.


2023년 일정 - 완료 4개, 진행 중 2개
  • 컴퓨터공학과 학부 졸업 (17.03 ~ 23.02)
  • 항해99 수료 (23.02 ~ 23.05)
  • 글또 8기 (23.02 ~ 23.07)
  • SSAC TDD 스터디 (23.03 ㄴ~ 23.04)
  • 삼성 청년 SW 아카데미 재학중 (23.07 ~ 현재)
    • 1학기 이수 (~ 23.11)
    • 1학기 공통 프로젝트 우수상 (23.12)
  • 글또 9기 (23.11 ~ 현재)

이렇게 적어보니 '생각보다 한 일이 많은가?' 싶은 생각도, 목표를 이루지 못해 아쉬웠던 생각도 드는 일정들이었던 것 같습니다.

잘 한건 왜 잘했는지, 못 한건 어떻게 하면 더 나아질 것인지 하나하나 뜯어보며 본격적인 회고를 해봅시다.

 

항해99 수료 (23.02 ~ 23.05)

 

참 아쉬움이 많은 항해99 활동이었습니다. 한 마디로 정리하자면,,

시작은 창대하나 그 끝은 미약하리라.

 

짧은 교육 수료 후 취업을 목표로 항해99를 신청한 저는 리액트반 1등을 노리고 있었습니다.

전공/비전공생이 섞인 이 교육에서 1등을 노리는 것은 당연한 일이 아니었을까.. 싶은 생각이었죠.

하지만 이는 참 어리석은 생각이었습니다.

 

여러 문제들이 있었겠지만 교육 초기, 건강과 성격 덕분에 팀원들과 네트워킹하는 시간을 덜 가진 것이 패착의 시발점이었을까요.

몇몇 분들과 친해지는 것을 성공했지만 리액트 반의 동기들과 친해지지는 못했습니다. 노력이 부족하다

그 덕분에 (100% 지분은 아니겠지만) 최종 프로젝트 주제 / 팀원 선정 시 어려움을 겪었던 것 같아요.

 

항해 덕에 많은 것을 알아갔지만, 가장 크게 깨달았던 것은 네트워킹의 중요성이었습니다.

 

글또 8기 (23.02 ~ 23.07)

 

하길 잘 했다고 느끼지만, 아쉬움이 많은 글또 8기입니다.

생애 처음으로 직장인이었다면 더 좋을 것 같다는 생각이 든 모임이죠. 그것이 취준생이니까

이 모임에서 처음으로 글을 규칙적으로 쓰는 연습, 잘 쓴 글들을 보는 연습, 글 관련 피드백을 주고 받는 커피챗 등 많은 것들을 행했었어요.

 

다만 이러한 활동을 하면서 제 스스로에게 아쉬움을 많이 느꼈어요.

우선, 제가 완벽주의 성향을 가진 편이라 그것이 무엇이든, 잘하는 것에서 즐거움을 느끼는 편입니다.

그렇기에 글, 블로그 플랫폼의 완성도부터 SEO, 퍼스널 브랜딩 등 : 심지어는 지역, 커피챗까지..

아쉬운 점은 한 두가지가 아니더군요.

 

그래도 개선점을 알아냈다는 점에서 의의를 두고 싶습니다. 문제가 생기면, 고치면 그만 아니겠어요?

이때부터 시작된 개인 블로그 제작, TDD를 곁들인 글 UI 개선 프로젝트 완성을 기대해주세요! (지금은 잠시 멈춰있지만)

 

SSAC TDD 스터디 (23.03 - 23.04)

 

메이커준님이 운영하시는 싹 채널에서 진행했던 TDD 스터디. 운이 좋게 참가할 수 있었습니다.

4주 동안 'TDD가 무엇인가, TDD는 어떤 방식으로 진행하는 가'를 공부하고 직접 실습해오는 그런 방식으로 진행했었습니다.

 

글또를 하면서 개발 블로그, 특히 티스토리 기본 템플릿의 개선점을 찾았기 때문에 이를 해결해보고 싶었습니다.

주제는 '개발 글의 UX 개선을 위한 UI 만들기'.

 

> 개발 글들은 코드를 보면서 개념 혹은 활용법을 이해하는 경우가 많다.

> 이는 독자의 읽는 시간을 증가시킨다. 이해를 하는데 시간이 오래 걸린다.

> 이러한 단점을 애니메이션을 만들어서 개선하면 조금 더 쉽지 않을까?

 

이러한 개인 목표를 가지고 스터디를 진행했으나 애니메이션을 TDD로 검사하는 과정에서 문제에 부딪히게 되었는데요.

그 문제는 바로 '애니메이션의 재생 여부를 어떻게 검사할 수 있을까' 였습니다.

여러 방법을 조사했었으나 특정 시점의 이미지를 비교할 수 있는 방법이 가장 유력한 방법이었습니다.

해당 방법을 이용하면 사람 입장에서 정상 동작 여부를 감지할 수 있었으나,, 코드는 그걸 알 수 있을까? 싶더군요.

 

그래서 해답을 찾을 때까지.. 해당 프로젝트를 잠시 쉬고 있습니다. (개인 블로그 제작과 더불어)

 

삼성 청년 SW 아카데미 (23.07 - 현재)

 

항해99 교육을 들으며 아쉬웠던 내 실력을 보강하기 위한 두 가지 방법 중 하나였습니다. 취업과 교육.

준비를 적게 했지만, 운이 좋게도 붙어서 지금은 교육생의 신분이 되었죠.

 

자바 기반의 웹 교육을 받으면서 '나는 프론트엔드가 하고 싶은데, 이 교육을 들어야 하나'라는 생각, 고민이 5만번은 들었던 것 같습니다.

얼마나 고민했으면, 교실에 있는 것만으로 가슴이 답답해서 조퇴를 할 정도였으니까요.

 

그러나 1학기가 끝난 지금, 올해 중 가장 잘한 선택은 이 선택이었던 것 같습니다.

부족했던 알고리즘에 대한 역량 향상, 프로젝트 및 협업 능력에 대한 증명 기회, 평균 학력을 대신할 수 있는 이름값.

위 세개를 한 번에 챙겨갈 수 있는 기회가 주어졌으니까요. 물론 취업 지원 등 다른 것도 많긴 합니다.

 

아직 교육이 끝나지 않았으니, 내년부터는 이 교육에 저를 갈아볼까 합니다.

3학년 때부터 외부 활동을 많이 했었지만 두드러지는 성과가 딱히 없던 제게 주어진 마지막 증명 기회니까요.

 

남은 3회의 프로젝트에서 수상, 해당 수상 기록을 기반으로 실습코치 지원, 가능하면 SSDC 오픈소스 프로젝트 참여까지.

시작하기도 전에 꺼질 위험에 부딪힌 제 커리어. 아직 살아날 수 있는 희망의 불씨가 보입니다.


 

이렇게 2023년 큼직큼직한 일정에 대해 회고를 해봤습니다.

올 해에 있던 일정들은 대부분 잘했다기보단, 아쉬움이 많았던 것 같습니다.

마무리를 잘 못하는 제 성격의 단점 탓이겠지만.. 이러한 점도 극복해나가고 있는 중이니까요.

잘 될 겁니다. 잘 되어야만 합니다 !

연말 회고를 했으니, 내년엔 이러한 잘못을 반복하지 않도록 열심히 살아봅시다.

열심히 한 만큼 몸값이 올라가는 게 개발자 아니겠습니까 !!

SSAFY란

SSAFY, 싸피는 삼성 청년 SW 아카데미의 줄임말로 문제 해결능력을 갖춘 경쟁력 있는 차세대 SW인력을 키우는 교육 프로그램으로
최고 수준의 맞춤형 교육, 자기주도적 학습, 효율적인 취업지원 서비스를 제공하는 싸피는 5개 캠퍼스에서 많은 인원을 교육하고 있습니다.
( 10기 기준, 1000명 이상 - 서울, 대전, 광주, 구미, 부울경 캠퍼스 )
이 외에도 교육지원금 지급, 국내외 연구소 실습 기회, 우수 교육생 시상, 통학버스 운행(서울 제외) 등을 지원합니다.

SSAFY 지원 자격

* 전공 무관 * SW 관련 전공생, 비전공생 모두 지원 가능 !!

만 29세 이하, 국내외 4년제 대학(학사 이상) 졸업자 및 졸업 예정자(23년 8월), 현재 미취업자 대상이며

  • 인터뷰일부터 본교육 시작일 전까지 재직(예정)자 지원불가
  • 교육시작일 교육 입과 가능한 자
  • 입과 후 1년간 SSAFY 교육에 온전히 집중할 수 있는 자
  • 교육기간 중 통학 가능한 자(별도 숙소 제공 없음)
  • 병역필 또는 면제자로 해외여행에 결격 사유가 없는 자

Tip 1. 교육 시작일 이전 전역자도 졸업 또는 졸업 예정자라면 지원 가능!
실제로 학점은행제를 이용해 부대 안에서 졸업 후 갓 전역한 상태로 교육에 참여하는 케이스도 있습니다 🔥

SSAFY 교육생 선발 절차

SSAFY는 1년에 2번(상반기, 하반기) 선발하며 10기 기준 선발 일정은 아래와 같습니다.

  • 지원서 접수 4.24(월) ~ 5.8(월)
  • SW적성진단 SW비전공 : 5.13(토), SW전공 : 5.21(일)
  • 인터뷰 6.7(수) ~ 6.13(화)
  • 입과 및 교육 23년 7월 시작

SSAFY 꿀팁 및 합격 인증

우선 합격 인증부터 !

> 10기 합격 인증 <

SSAFY 지원 시 꼭 거쳐야 할 3관문은 바로 에세이, 적성진단, 인터뷰!

각 관문당 하나씩 꿀팁 풀어보겠습니다.

에세이 꿀팁 - 본인 소개와 미래의 내 모습 포함하기

에세이를 쓰는 이유는 인터뷰 기회를 얻기 위함입니다. 그러기 위해서는 지원자가 알고 싶은 사람이 되어야 합니다.

왜 개발을 하고 싶은지 본인의 이야기를 솔직하게 풀어내면서 300자 내외로 적어주세요.

다 적으셨다면 교육이 끝났을 때 어떤 사람이 되고 싶은지 적어주세요. 

 

삶의 지도 기반으로 제 이야기를 해볼게요. 합격 에세이 아니에요!! https://ladiescheong.tistory.com/38


저는 컴퓨터가 좋아서 컴퓨터 전공생이 되었어요. 그런데 막상 전공생이 되고 나니 공부하기 싫었어요.

그토록 배우고 싶었던 컴퓨터인데, 왜일까요? 

 

그 이유는 서비스 혹은 프로그램들을 왜 만들고 싶은지를 모르는 것이었어요.

개발을 잘 못하는 건열심히 하면 되죠. 그런데 시키는 대로, 혹은 스스로 공부하다보니 개발을 하고 싶은 이유를 모르겠더라구요.

 

이유를 찾던 중, 유튜브 EO 채널에서 배달의민족 김범준 CEO님의 인터뷰를 보고 이유를 찾게 되었어요.

이제부터 제 목표는 개발로 문제를 해결하는 사람이 되는 것이었어요.

 

그 목표를 이루기 위해 저는 무엇을 했을까요?

개인적으로 코딩 공부도 했지만 공모전, 해커톤 등에 참여해서 어떻게 문제를 정의하고 서비스를 개발하는지 등을 배웠어요.

그리고 코딩 실력을 기르기 위해서 부트캠프에도 참여했어요.

 

이럼에도 불구하고 뭐가 부족해서 싸피 교육에 참여하고 싶었을까요?

전공생으로 위와 같은 활동들에 참여하다보니 알고리즘 & CS 지식이 모자랐어요.

 

그래서 싸피 교육을 들으면서 부족한 것들을 공부하고 싶었었어요.


제 이야기 어떠셨나요? 괜찮았나요? 쓰다보니 삶의 지도에 없는 내용도 있었네요 🥲 업데이트가 필요하군요

이러한 내용을 적을 수 있는 정도로 본인이 어떤 삶을 살았는지, 무엇을 했는지 곰곰히 생각해보고 적으시면 도움이 될 거에요.

 

적성진단 꿀팁 - 공부 전 시험이 어떻게 이루어지는 지 찾아보기

시험에서 요구하는 능력은 분명히 정해져있어요.
전공생은 IM 등급 정도의 문제들이 출제됩니다. 구글에 검색해보시면 후기가 참 많아요.

저는 이걸로 공부하진 않았지만 IM 수준의 문제 리스트가 있네요! https://www.acmicpc.net/workbook/view/10168 

 

문제집: SW 역량테스트 IM 수준 (dbdjfdjqkqh1)

 

www.acmicpc.net

시험에서 요구하는 것을 알게 되면 범위를 줄일 수 있어 효율적인 학습이 가능하다는 사실! 꼭 기억하셔서 써먹어보세요.

 

인터뷰 꿀팁 - 본인의 장점을 정리해서 예상 질문 답으로 준비하기

면접 후기를 검색하면 예상 질문 리스트들이 있어요. 자주 나오는, 겹치는 것들을 추려보세요.
그 후 에세이를 쓰면서 본인이 가진 강점들을 어떤 질문에 사용할 수 있을지 고민해보세요.

 

예를 들면 저는 싸피 교육이 힘듦, 할 수 있음? 질문에 강점 1을 넣었습니다.

'최근에 다른 부트캠프를 하면서 99일동안 1000시간이 넘도록 참여했다. 당연히 싸피도 할 수 있다'

이러한 방식으로 내 강점을 최대한 어필할 수 있는 내용들을 답으로 준비해보세요.

 

단, 내가 코딩을 얼마나 잘하는 지 어필하는 것은 마이너스 요소가 될 수 있어요! 

교육 프로그램이기 때문에 잘 하는 사람보다 잘 할 수 있는 사람을 뽑으니까요.

 

마무리

싸피 소개와 합격 관련 꿀팁 이야기, 흥미로우셨나요?

더 궁금한 것이 있다면 댓글로 남겨주세요 🙇🏻‍♂️

항해99를 할까 말까 고민하고 있는 당신. 잘 찾아왔습니다.

13기 수료생 입장에서 0 to 99까지 이야기해볼게요.

 

다짜고짜 수료 인증

 

결론부터 말하자면 전공 여부와 상관 없이 열심히 하고 친화력 높은 사람일수록 좋습니다.

 

이제 대충 제 이야기를 해볼게요.

저는 여러 공모전 및 해커톤에 참가한 경험이 있는 4년제 지방대 전공생, 프론트엔드 지망생입니다.

전공생이니까, 당연히 개발자가 되고 싶었어요. 컴퓨터 화면엔 의미를 알 수 없는 영어떼기들, 터미널 화면에 올라오는 프로그램 로고.

멋있지 않나요?

 

그래서 졸업하고, 여행 갔다오고 나서 취업을 하려고 보니 대부분 좋은 기업들은 경기도(판교, 성남), 서울에 있더군요.

저는 지방대생이라, 서울까진 연줄이 없었어요 아싸 대학생. 그럴만한 실력도 안 된다고 판단했구요.

그래서 부트캠프를 알아보기 시작했습니다.

 

제가 고민했던 부트캠프 리스트와 이유는 다음과 같아요.

 

1. 우아한테크코스 : 탈락

2. SSAFY : 프론트엔드 과정이 따로 없음

3. 앨리스, 코드스테이트 등 국비 부트캠프

4. 항해99

 

3, 4번 중에서 고르는 게, 이게 참 어려웠던 선택이에요. 무엇을 해야 할까...

결론적으로 항해 99를 선택했던 이유는 솔직히 짧은 기간, 많은 팀 프로젝트가 매력적이어서 골랐어요.

비용이야, 처음에 조금 내고 취업하고 나서 내면 되겠지 생각했구요.

 

그래서 항해99를 지원했답니다.


항해99 생활은 어땠냐? 할만한가 물어보신다면 저는 만족하면서 생활했습니다.

 

 

항해99 이전에 후기들을 살펴보면 방임/방치, 팀원 문제들이 주로 언급되던 걸 봤습니다.

 

방임/방치 문제는 제가 항해99를 할 때도 이야기가 나왔던 부분이긴 해요.

다만 이게, '진짜 방치해둔다' 이런 느낌보다는 의도적으로 방치해둔 느낌? 입니다.

팀원들끼리, 동기들끼리 찾아보고 고민하고 생각해보라는 의미에서 기술 관련해서는 명확한 정답을 알려주지 않아요.

대신 기술 매니저님들이 거의 매일, 주말까지도 질문 받으러 순회를 다니십니다. 담임 매니저님의 멘탈 케어는 덤이구요.

 

그래서 앞서 이야기했던 것처럼 친화력이 좋고 열심히 하는 분일수록 얻어가는 게 많습니다.

가만히 있으면 조금 덜 얻어가요.

 

팀원 문제는 뭐.. 사실 다 알잖아요? 조별 과제하면 한 두명씩은 문제가 생기는 거.

제가 생활할때도 그런 문제가 있긴 했었는데, 저는 팀원 관련해서 문제가 없었어요. 암 쏘 럭키

오히려 다들 사비로 부트캠프를 다니다 보니까 열심히 하는 사람들이 진짜 많았어요. 그건 진짜 소중한 장점입니다. 

 

그래서 저는 만족하고 다녔어요. 거의 매일 찾아오는 기술 매니저님 + 열심히 하는 동료 + 의견 잘 받아주고 멘탈 케어하는 담임 매니저님

이런 곳이면 어떤 일을 하든 만족하지 않을까요? 너무 광고같았나

 

광고 아니니까.. 이제 항해99 단점을 말해볼게요.

전공생 입장에서, 초반에 조금 지루할 수 있습니다.

저는 항해99를 하면서 실전 프로젝트 이전까지 알고리즘, TDD 스터디 및 글쓰는 모임 활동을 병행했어요. 약 30일정도?

가면 갈수록 힘들어지긴 했지만요. 

 

비전공생 입장에서, 진도를 따라가기가 힘들어요.

그날 그날 주어진 과제 다 하고, 복습 및 추가 공부를 철저히 해야 생존할 수 있습니다.

실제로 중간에 포기하시는 비율도 많고, 힘들어서 우는 분들도 많습니다. 진짜로. 나중에 취직하실 때 장점이 되긴 합니다

 

그래서, 넌 항해99 풀타임을 추천하냐 추천하지 않냐? 그것만 말해봐 라고 하신다면,

1. 비전공생은 항해99에서 생존해보세요. 살아남는 자가 강한 자입니다. 당신은 강한가요?
2. 코딩 경험이 적은 전공생, CS가 탄탄한 전공생은 항해99 추천.

이런 사람들을 추천해요.

 

댓글로 궁금한 것들을 남겨주시면 성심성의껏 대답해드리겠습니다. i want you

저는 프론트엔드 개발자로 취직하기 위해 1달 정도 이력서를 준비했습니다.
이력서 관련 팁과 첨삭을 받으면서 느낀 부분들을 정리하면 도움이 될 것 같아서 글을 써봅니다. 아직 취준 중이긴 하지만??

자세한 이야기를 하기 전에, 이력서는 정답이 없습니다!! 외치고 가야됩니다. 진짜로.

사람마다 생각도 다르고 선호하는 부분도 달라서 어떻게 이력서를 만들지 본인이 선택하셔야 합니다.

다만 가장 확실한 기준이 하나 있습니다. 바로 지원했을 때의 서류 합격률 ! 근데 그건 저도 어떻게 해야하는지 몰라요

많이 지원하셨는데 서류 합격률이 낮다면 이력서를 재수정하셔야 합니다.

사족은 치워두고, 이력서에 쓸 수 있는 항목들을 먼저 알아봅시다.

이력서에 기재할 항목들은 한 줄 소개, 연락처, 회사 경험, 프로젝트/토이 프로젝트, 대외활동, 학력사항, 언어, 수상 경력입니다.
이 중 하나라도 없거나 썼을 때 도움이 되지 않을 것 같다면 생략하면 됩니다.


저는 소개 / 연락처 / 정보 / 프로젝트 / 대외활동 / 학력사항 등을 기재했습니다.


그렇다면 어떻게 이력서를 써야 할까요? 필수 항목부터 알아봅시다.

 

이력서를 쓸 때

  • 여러 개의 항목을 나열하는 경우 시간 순으로 나열하기
  • 내용 및 기간 등을 명확하게 명시하기
  • 성과를 적절한 숫자로 표기하기 - 프로젝트의 성능 개선 등
  • 프로젝트에서 맡은 역할과 본인이 한 일을 명확히 명시하기
  • 연락처의 이메일, 깃허브 등을 URL로 기재하기

이력서를 정리할 때

  • 이력서의 가독성 체크하기 - 모바일로도 읽어보기
  • 프로젝트 등의 한 영역이 한 페이지 내에 위치하도록 수정하기
  • 연락처가 맨 앞 장, 찾기 쉬운 곳에 있는지 체크하기
  • 본인 강점 등의 근거를 이력서 또는 포트폴리오에서 찾아볼 수 있는지 확인해보기
  • 이 경험이 개발자가 되기 위해 필요한 경험 또는 어필할 수 있는 경험인지 생각해보기
  • 하이퍼링크 정상 작동 확인하기
  • 맞춤법, 띄어쓰기, 오타 확인하기

 

선택 사항은 다음과 같습니다. 이게 제일 중요합니다 !!

 

이력서를 쓸 때

  • 맨 앞장에 본인이 어떤 사람인지 잘 드러나게 쓰기
    내 능력을 어필하는 것도 좋지만, 내가 어떤 사람인지 표현할 수 있는게 이력서의 장점
  • 업무 목적과 결과를 문제 / 시도(근거) / 결과 순으로 명확하게 쓰기
    신입 개발자일수록 실력보다 생각하는 과정을 중요시하는 분들이 많다. 특히 라이브러리!!!
    요즘 유행하는 기술이라고 그냥 갖다 쓰면 안된다. 면접가면 탈수기 돌려진다.
  • 내 모습 또는 개발과 관련 없는 내용은 과감히 패스하기

이력서를 정리할 때

  • 본인 이력서에서 키워드를 뽑은 뒤 해당 키워드가 이력서에 설명이 되어 있는지 찾아보자.
    없다면 면접에서 물어볼 가능성이 많다. → 근거 말고 키워드 !!

 

어떤 형식에도 위 내용을 지켜서 이력서를 쓰게 된다면 충분히 좋은 이력서가 나올 겁니다.

기술 스택에 숙련도를 별로 기재하지 마라 이런 건 너무 이력서 형식 관련 이야기라서.. 굳이 이야기 하지 않았습니다.

이 글을 쓰기 위해서 인텔리픽, f-lab 블로그 등을 참고했고, 포코님의 팁, 개인적으로 받은 피드백들을 정리했습니다.

도움을 주신 모두에게 감사하다는 말씀 드립니다 !

이전 시간에 Headless UI 기반의 추상화를 얘기했었습니다.

기억나시나요? 간단하게 리마인드 해봅시다.

 

이런 코드에서

function StudyList() {
  const [studys, setStudys] = useState([]);

  const getStudys = async () => {
    const { data } = axios.get('api server url');
    return data;
  };

  useEffect(() => {
    setStudys(getStudys);
  }, []);

  const studyOnClickHandler = () => {
    window.location.reload('study detail url');
  };

  return (
    <ul>
      {studys.map(study => {
        <li key={study.id}>
          <StudyArticle
            {...study}
            onClick={studyOnClickHandler}
          />
        </li>;
      })}
    </ul>
  );
}

이런 코드까지.

function StudyList() {
  const [studys, setStudys] = useStudys();

  return (
    <ul>
      {studys.map(study => {
        <li key={study.id}>
          <StudyArticle
            {...study}
            onClick={studyOnClickHandler}
          />
        </li>;
      })}
    </ul>
  );
}

데이터 및 상호작용을 추상화해 컴포넌트 안에서 UI 로직에 집중할 수 있게 되었죠.

이제 이 UI 로직을 잘 짜면 될 것 같은데, 어떻게 하면 잘 짤 수 있을까요?

변경에 유연한 컴포넌트, 어떻게 만들어야 할까요?

 

그 답은 한 가지 역할만 하는 컴포넌트들의 조합으로 만들어야 합니다.

 

자, 예를 들어 아래와 같은 컴포넌트를 만들어야 한다고 합시다.

 

이 컴포넌트에서 꼭 필요한 요소가 어떤 것이 있을까요?

온/오프라인, 등록 시간, 북마크, 제목, 회사, 마감일, 금액이 있겠네요.

 

그렇다면 이 요소들을 가지고 있는 공고 UI를 하나 만들면 되겠네요.

근데 어떻게 만들까요? 어떤 디자인 패턴을 쓰면 좋을까요?

음.. 아토믹 디자인 패턴으로 만들어볼까요?

아토믹 디자인 패턴을 모른다면 클릭!

 

온/오프라인, 등록 시간, 북마크, 제목, 회사, 마감일, 금액을 각각 순서대로

Place, Time, Bookmark, Title, Company, EndDate, Pay라고 해봅시다.

 

이 때, StudyArticle 컴포넌트는 어떻게 될까요?

import Place from 'Place';
import Time from 'Time';
import Bookmark from 'Bookmark';
import Title from 'Title';
import Company from 'Company';
import EndDate from 'EndDate';
import Pay from 'Pay';

// 아무런 스타일을 적용하지 않았을 때
function StudyArticle() {
  return (
    <article>
      <Place />
      <Time />
      <Bookmark />
      <Title />
      <Company />
      <EndDate />
      <Pay />
    </article>
  );
}

// 스타일을 적용할 때
function StudyArticle() {
  return (
    <article>
      <Flexbox>
        <Place />
        <div>
          <Time />
          <Bookmark />
        </div>
      </Flexbox>
      <Company />
      <Title />
      <Flexbox>
        <EndDate />
        <Pay />
      </Flexbox>
    </article>
  );
}

 

이런 식으로 표현할 수 있을 것 같아요.

자, 여기서 각자 atomic 컴포넌트로 분리했어요. 그렇다면 데이터는 어떻게 관리해야 할까요?

가장 쉬운 방법은 StudyArticle에서 props로 내려주는 것이겠죠? 해봅시다.

 

import Place from 'Place';
import Time from 'Time';
import Bookmark from 'Bookmark';
import Title from 'Title';
import Company from 'Company';
import EndDate from 'EndDate';
import Pay from 'Pay';

// props는 StudyList에서 내려주고 있습니다.
function StudyArticle({ place, time, bookmark, company, title, endDate, pay }) {
	return (
    <article>
      <Flexbox>
        <Place place={place} />
        <div>
          <Time time={time} />
          <Bookmark bookmark={bookmark} />
        </div>
      </Flexbox>
      <Company company={company} />
      <Title title={title} />
      <Flexbox>
        <EndDate endDate={endDate} />
        <Pay pay={pay} />
      </Flexbox>
    </article>
  );
}

자, 열심히 시간을 들여서 StudyArticle 컴포넌트를 무사히 완성했어요! 정말 기쁘네요.

기쁨을 느낄 새도 없이, 디자이너가 ‘홈 화면에서 보여질 작은 공고 UI’라는 비슷한 UI 생성 요청을 해왔어요.

음.. 이건 좀 다르네요? 북마크와 회사 위치, 마감일과 금액의 위치는 변해있고, 등록 시간은 없네요.

뭐,, 아까처럼 하면 만들 수 있지 않을까요?

 

이때, 디자이너가 너무 열일한 나머지 ‘마이페이지에서 보여질 공고 UI’ 컴포넌트 제작을 요청해요.

이것도 뭐 기존 스터디 UI에서 크게 벗어나지 않긴 하네요. 근데 뭔가 불안해요.

매번 비슷한 컴포넌트 제작을 요청받을때마다 중복이 너무 많은 컴포넌트를 만드는 것 같아요.

무언가 좋은 방법 없을까요?

 

이럴 때 컴파운드 컴포넌트 패턴을 이용해봐요. 일단 코드를 봅시다.

// 기본 실험 공고 UI
function Study1() {
  return (
    <article>
      <Flexbox>
        <Study.Place />
        <div>
          <Study.Time />
          <Study.Bookmark />
        </div>
      </Flexbox>
      <Study.Company />
      <Study.Title />
      <Flexbox>
        <Study.EndDate />
        <Study.Pay />
      </Flexbox>
    </article>
  );
}

// 마이페이지에서 보여질 공고 UI
function Study3() {
  return (
    <article>
      <Flexbox>
	  	<Study.Company />
		<Study.ApplyDate />
      </Flexbox>
      <Study.Title />
      <Study.Pay />
      <Flexbox>
		<div>
          <Study.Address />
          <Study.EndDate />
        </div>
        <Study.IsRead />
      </Flexbox>
    </article>
  );
}

어.. 아까랑 크게 다르지 않은 것 같은데요? 뭐가 다른건가요?

결론부터 이야기하면 Study 컴포넌트를 활용해서 새로운 컴포넌트를 쉽게 만들 수 있어요.

그리고 각 컴포넌트에 데이터를 일일히 내려주지 않아도 괜찮아요.

즉, 온전히 스타일에 집중할 수 있게 되었어요.

 

음.. 그런가? 그렇다면 어떻게 컴파운드 컴포넌트를 만들어요?

컴파운드 컴포넌트는 아래 코드를 보면서 살펴봐요.

일단 필요한 데이터를 3개 정도만 추려서 소개해볼게요.

// 컴포넌트에서 공유될 상태를 정의
const StudyContext = React.createContext({
  company: '',
  title: '',
  pay: '',
});

// Context API를 통해 상태 공유
const StudyWrapper = ({ company, title, pay, children }) => {
  const contextValue = { company, title, pay };
  return (
    <StudyContext.Provider value={contextValue}>
      {children}
    </StudyContext.Provider>
  );
};

// Context API를 통해 상태 전달 받기
const Company = ({ ...props }) => {
  const { company } = React.useContext(StudyContext);
  return <div {...props}>{company}</div>;
};

const Title = ({ ...props }) => {
  const { title } = React.useContext(StudyContext);
  return <h2 {...props}>{title}</h2>;
};

const Pay = ({ ...props }) => {
  const { pay } = React.useContext(StudyContext);
  return <div {...props}>{pay}</div>;
};

// 함수 = 객체이므로 자식 컴포넌트를 속성으로 할당
StudyWrapper.Company = Company;
StudyWrapper.Title = Title;
StudyWrapper.Pay = Pay;

아래와 같은 순서대로 하면 돼요.

  1. 컴포넌트에서 공유될 상태를 정의해요.
  2. 부모 컴포넌트를 만들고, Context API를 이용해 상태를 공유해요.
  3. 자식 컴포넌트를 만들고, Context API에서 상태를 전달받아 사용해요.
  4. 부모 컴포넌트에 자식 컴포넌트를 속성으로 할당해서 외부 컴포넌트에서 사용할 수 있도록 만들어요.

어.. 두 가지 질문이 있어요.

  1. 왜 Context API를 사용해요? 리덕스 같은 툴도 사용할 수 있지 않나요?
  2. 위 코드에서는 데이터 값만 공유하는 것 같아요. 다른 상태도 공유할 수 있나요?

아주 좋은 질문이에요. 1번 질문에 대한 답은 다음과 같아요.

컴파운드 컴포넌트 패턴으로 컴포넌트를 작성한다는 것은, 여러 곳에서 해당 컴포넌트를 사용하기 때문이에요.

이 말은 즉, 동일한 컴포넌트에서 다른 상태를 가질 수도 있다는 의미에요.

리덕스는 싱글 스토어라서 한 개의 상태가 모든 컴포넌트에서 공유돼요. 그래서 Context API를 사용해요.

 

2번 질문에 대한 답은 다음과 같아요.

데이터 값만 공유하지 않아도 돼요. 예를 들면 북마크 상호작용 함수를 공유할 수도 있죠.

객체니까 필요하다 싶으면 공유할 수 있도록 선언해주면 돼요.

 

글이 길었네요. 정리를 해볼까요?

정리

여러 곳에서 비슷한 컴포넌트를 사용하고 싶다면 컴파운드 컴포넌트 패턴을 이용해봐요.

 

컴파운드 컴포넌트는 아래와 같은 순서로 만들어요.

  1. 컴포넌트에서 공유될 상태를 정의해요.
  2. 부모 컴포넌트를 만들고, Context API를 이용해 상태를 공유해요.
  3. 자식 컴포넌트를 만들고, Context API에서 상태를 전달받아 사용해요.
  4. 부모 컴포넌트에 자식 컴포넌트를 속성으로 할당해서 외부 컴포넌트에서 사용할 수 있도록 만들어요.

 

참고 자료

https://fe-developers.kakaoent.com/2022/220505-how-page-part-use-atomic-design-system/

 

아토믹 디자인을 활용한 디자인 시스템 도입기 | 카카오엔터테인먼트 FE 기술블로그

정호일(harry) 카카오페이지에서 웹 프론트엔드를 개발하고 있습니다. 집보다 밖에 돌아다니는 걸 좋아합니다.

fe-developers.kakaoent.com

https://www.youtube.com/watch?v=aAs36UeLnTg 

 

최근에 팀 프로젝트에서 6주동안 프론트엔드 2명이서 31개의 페이지를 구현하는 일을 맡았습니다.
저는 일정이 빡빡하다 보니 한 페이지 컴포넌트에 기능과 UI 모두를 기술하고 사용하고 있었어요.
나중에 분리하면 되겠지라는 안일한 마음으로

그런데 서비스를 개발하다보니 재사용성이 필요한 컴포넌트들도 많고 변경점도 많더군요. 세상에. 저는 죽었습니다
이 프로젝트를 무사히 끝낼 수 있을까? 어떻게 하면 시간이 덜 걸리면서 페이지를 구현할 수 있을까? 를 고민하기 시작했습니다.

 

비슷하지만 다른 페이지들을 구현하다보니 기능과 UI에 대해 공통점이 보이기 시작했고 이를 컴포넌트로 분리해서 재사용을 하자! 라고 생각하기에 이르렀습니다. 그런데 비슷한 기능임에도 다른 UI를 가지고 있거나, 기능은 다르지만 비슷한 UI를 가지고 있었습니다. 머리 아프다

어떻게 하면 변경에 유연하고 재사용성이 뛰어난 컴포넌트를 만들 수 있을까요?

우선, 가장 많이 도움을 받은 영상을 소개합니다. 외쳐 재엽갓 토스갓

해당 영상에 따르면 잘 만들어진 컴포넌트의 기준을 3가지로 제시합니다.

잘 만들어진 컴포넌트

  1. Headless UI 기반의 추상화
  2. 한 가지 역할만 하기
  3. 도메인 분리하기

여기서 Headless UI 기반의 추상화가 무슨 의미일까요?

 

Headless는 간략하게 UI를 제외하고 데이터에만 집중해 모듈화 하는 것입니다.

즉, 컴포넌트에서 데이터와 상호작용을 추상화하는 것이죠.

 

예를 들어 스터디 목록을 받아와 보여주는 StudyList 컴포넌트가 있다고 합시다.

function StudyList() {
  const [studys, setStudys] = useState([]);

  const getStudys = async () => {
    const { data } = axios.get('api server url');
    return data;
  };

  useEffect(() => {
    setStudys(getStudys);
  }, []);

  const studyOnClickHandler = () => {
    window.location.reload('study detail url');
  };

  return (
    <ul>
      {studys.map(study => {
        <li key={study.id}>
          <StudyArticle
            {...study}
            onClick={studyOnClickHandler}
          />
        </li>;
      })}
    </ul>
  );
}

우리가 위 컴포넌트에서 기대하는 기능은 총 세 개입니다.

  1. 서버로부터 스터디 데이터를 불러와 상태로 관리하기
  2. 상태를 기반으로 데이터를 보여주기
  3. 유저와 상호작용하기

여기서 데이터와 상호작용에 해당하는 부분을 추상화해봅시다. 어떻게 하면 될까요?

 

위 코드에서 데이터 로직은 3단계로 정의할 수 있습니다.

  1. 페이지가 렌더링 되었을때(useEffect) 
  2. 서버로부터 데이터를 불러오고(getStudys)
  3. 불러온 데이터를 상태로 관리하는(setStudys)

일단 이 3단계를 모두 하나로 묶어서 커스텀 훅으로 분리합니다.

// 데이터 추상화
function useStudys() {
  const [studys, setStudys] = useState([]);

  const getStudys = async () => {
    const { data } = axios.get('api server url');
    return data;
  };

  useEffect(() => {
    setStudys(getStudys());
  }, []);

  return [studys, setStudys]
}

그런 다음 이 커스텀 훅에서 리액트 훅을 쓰지 않아도 되는 부분을 고민해봅시다.

이 코드에서는 서버에서 데이터를 불러오는 함수는 훅을 쓰지 않아도 되겠네요.

해당 부분을 분리해봅시다.

// useStudys.jsx
function useStudys() {
  const [studys, setStudys] = useState([]);

  useEffect(() => {
    setStudys(getStudys());
  }, []);

  return [studys, setStudys]
}

export default useStudys;

// api.js
export const getStudys = async () => {
  const { data } = axios.get('api server url');
  return data;
};

더 분리하고 싶은 부분이 있나요? 데이터는 추상화가 모두 끝난 것 같고 상호작용 정도 분리할 수 있겠네요.
상호작용 추상화는 이 코드에서 정말 간단하니까 생략하도록 하겠습니다.

그럼 데이터를 추상화하기 전과 후의 StudyList 컴포넌트를 비교해봅시다.

// 분리하기 전
function StudyList() {
  const [studys, setStudys] = useState([]);

  const getStudys = async () => {
    const { data } = axios.get('api server url');
    return data;
  };

  useEffect(() => {
    setStudys(getStudys);
  }, []);

  const studyOnClickHandler = () => {
    window.location.reload('study detail url');
  };

  return (
    <ul>
      {studys.map(study => {
        <li key={study.id}>
          <StudyArticle
            {...study}
            onClick={studyOnClickHandler}
          />
        </li>;
      })}
    </ul>
  );
}

// 분리한 후
function StudyList() {
  const [studys, setStudys] = useStudys();

  return (
    <ul>
      {studys.map(study => {
        <li key={study.id}>
          <StudyArticle
            {...study}
            onClick={studyOnClickHandler}
          />
        </li>;
      })}
    </ul>
  );
}

 

 

데이터 로직에 대한 부분이 모두 분리됨에 따라서 StudyList 컴포넌트의 코드 수와 부담이 줄어들었습니다!
데이터 로직, 서버로부터 데이터를 받는 로직, 클릭 시 이동하는 로직을 분리함에 따라 다른 컴포넌트에서도 재사용할 수 있게 되었네요.


StudyList 컴포넌트는 많은 부분들이 추상화됨에 따라 이전보다 훌륭한 컴포넌트가 되었습니다.
그런데 여기서 더 개선할 수 없을까요?

다음 시간에는 한 가지 컴포넌트가 한 가지 역할만 할 수 있도록 분리하는 방법을 이야기하겠습니다.
읽어주셔서 감사합니다.

 

참고자료

  1. Headless UI에 대해 더 알고 싶다면?
    https://jbee.io/react/headless-concept/
  2. 위 영상을 다시 보고 싶다면? 
    https://www.youtube.com/watch?v=fR8tsJ2r7Eg

 

 

서론

감사하게도 최근에 메이커준님이 진행하는 TDD 스터디에 참가할 수 있었습니다.

저는 TDD 스터디에 참가하면서 TDD란 무엇이고 왜 이것을 해야하는지, 어떻게 하는 것인지 감을 잡게 되었습니다.

우리가 쉽게 검색해서 접할 수 있는 내용들과는 약간은 결이 다른 내용, 핵심이 다른 내용이라고 느껴졌고,

그래서 이 경험을 다른 분들한테 공유하고 싶어 글을 쓰게 되었습니다.

 

이 글을 빌어 메이커준님께 감사의 인사 드립니다. 

 

경험을 읽고, 교육을 하는 메이커준입니다.

👋🏼 메이커준 초간단 소개

www.makerjun.com


우선 TDD가 무엇이고 어떻게 쓰고 이런 것은 방법, 수단의 영역입니다.

제 의견은 "이러한 것(방법, 수단)들은 동기나 문제가 충분히 정의되지 않았을 때 공부하는 것은 큰 의미가 없다" 입니다.

그래서 동기와 TDD를 사용해서 해결하고 싶은 문제들을 이번 글에서 풀어보고자 합니다.

 

동기 - 왜 TDD를 배우려 했는가

두 가지 이유가 있습니다.

 

우아한테크코스 프리코스에서 테스트 코드를 작성하고, 이를 통과하는 코드를 짜는 활동들을 했었습니다.

TDD가 무엇인지, 이것을 왜 해야하는지 모르는 상태에서 위와 같은 활동을 했었고

매번 테스트 코드를 작성하고 원래 코드에 맞춰 수정하는 일이 빈번했습니다.

 

이렇게 TDD를 서툴게 활용했을 때, 놀랍지만 제가 얻는 이득이 존재했습니다.

 

1. 테스트 코드를 작성하면서 이 기능의 역할, 반환값, 예외 등을 코드 작성 이전에 고민하고 작성할 수 있었다는 것

2. 이 기능이 정확히 작동하는지 빠르게 알 수 있었다는 것

 

그래서 저는 이 TDD라는 것을 공부해보고 싶었습니다.

 

 

다른 하나는 너무나 현실적인 이유입니다.

 

프론트엔드 채용 공고 내 우대 사항에 테스트 자동화/TDD 등의 내용이 상당히 많았습니다.

전통적 / IT 대기업, 중견 기업, 스타트업 가릴 것 없이 프론트엔드 JD에 테스트 관련 언급들이 굉장히 많았었어요.

즉, 내가 취업을 하기 위해서 TDD를 공부해보는 것이 유리하겠구나 생각할 수 있게 되었던 지점이었습니다.

 

프론트엔드 개발자 채용 정보 | 트레이디

트레이디는 대한민국을 넘어 세계로 미래로 뻗어가는 스타트업이에요. 빅데이터 기술력을 바탕으로 경제, 비즈니스, 생활 속 다양한 사회적 문제를 해결하고 있습니다. 뉴스경제 정보, 생활 속

www.rocketpunch.com

 

토스채용

공고 자세히 보기

toss.im

 

 

 

이젠 TDD를 왜 배우고 싶었는지 이야기를 다 했으니, 해결하고 싶은 문제 이야기를 해볼까 합니다.

 

저는 이전부터 글을 잘 쓰고 싶었습니다.

왜냐하면 잘 쓴 글과 이미지, 영상들로부터 많은 도움을 받고 성장했기 때문입니다.

즉, 다른 사람들의 멋진 글을 보며 성장했었기에 잘 쓴 글 하나가 미치는 영향력을 몸소 깨닫게 된 것이죠.

 

이제는 저도 글을 잘 써서 다른 분들한테 좋은 영향을 주고 싶었습니다.

본인이 가진 역량을 드러내면서 타인에게 좋은 영향을 주는 것 중 제일 좋은 것은 지식 나눔이고

지식 나눔 중에서도 가장 대중적인 방법이 글쓰기라고 생각했기 때문이에요.

그래서 이렇게 글을 쓰고 있는게 아니겠어요?

 

그래서 글을 쓰기 시작했고, 글을 쓰다 보니 제 글이 마음이 들지 않다는 생각이 매번 들었어요.

왜 그랬을까요?

 

문제 정의

문제를 이야기하기 전에 제 글을 가져와 보겠습니다.

얕은 복사와 깊은 복사

 

위 글을 읽으면서 어떤 생각이 드셨나요? 이해는 쉽게 되셨나요?

저는 제가 쓴 글을 읽으면서 독자님들이 쉽게 이해할 수 없다고 생각했어요.

 

재그지그의 개발 블로그로도 유명하신 정종윤님도 저와 같은 생각을 했는지

개인적으로 이렇게 복잡한 주소 관계를 나타내는 경우에는 다이어그램이 있으면 더 이해하기 쉬웠던 것 같아요!

라고 피드백을 주셨습니다. (감사합니다 종윤님!!)

 

정리하자면

문제는 "이해를 돕기 위한 이미지가 없는 것"이고 이유는 "이미지 없이 내용을 이해하기 어려우니까"라고 정의할 수 있었습니다.

 

그런데 문제가 그것만 있었을까요?

 

저는 위의 문제에도 동의하지만, 그것만이 문제라고 생각하지 않았어요.

그것보다 더 집중했던 문제는 글의 구성, 레이아웃이었습니다.

 

 

이전에 아이패드용 스위프트 플레이그라운드라는 앱을 즐겨했었어요.

저는 이 앱을 사용하면서 매우 흥미로웠습니다.

이 앱은 일반적인 글의 형태와 조금 다를지도 모르지만, 제게 글과 이미지가 세로로 나열된 것보다 더 좋은 사용자 경험을 주었어요.

그래서 이런 방식으로 글을 구성하면 어떨까, 더 이해하기 쉽지 않을까? 싶었습니다.

 

 

글이 조금 길어졌으니 다음 글에서 문제 분석과 TDD 정의, 한 사이클을 적용한 결과 등에 대해서 이야기를 해보겠습니다.

읽어주셔서 감사합니다.

얕은 복사와 깊은 복사.. Shallow Copy vs Deep Copy

정말 헷갈리는 부분이 많았다. 정말로.

이제는 그만 헷갈리고자, 총 정리를 해보려한다.


0. 알아야 할 사전 지식

얕은 복사와 깊은 복사를 알기 전에 자바스크립트의 데이터 타입과 메모리 동작을 이해하는 것이 우선이다.

데이터 타입은 크게 원시형 / 참조형으로 구분되어있고 어떤 데이터를 변수에 저장하느냐에 따라 동작이 달라진다.

원시형을 먼저 살펴보자.

// 변수 a에 숫자 1을 할당하는 예시    
var a = 1;
1. &27의 값에 undefined를 할당한다.
2. 식별자 a에 &27을 할당한다.
    (& 기호는 메모리 주소를 의미한다. &27은 메모리의 27번 주소)
3. 새로운 공간인 &37에 1을 저장한다.
4. a에 &37을 할당한다.

 

원시형 데이터는 이런 방식으로 변수를 선언하고 할당한다.

참조형은 어떻게 다를까?

// 변수 obj에 객체를 할당하는 예시
var obj = { name: 'jin' }
1. &27의 값에 undefined를 저장한다.
2. 식별자 obj에 &27을 할당한다.
    (& 기호는 메모리 주소를 의미한다. &27은 메모리의 27번 주소)
3. 새로운 공간인 &37에 객체를 저장할 공간의 주소인 &12를 할당한다.
    즉, &37번 주소의 값이 &12이다.
    원시형 데이터는 &37번 주소의 값이 1이었다.
4. &12(name)에 'jin'이라는 문자열 값을 저장한다.
5. obj에 &37을 할당한다.

결과
: obj 변수의 값은 &37이며, &37에는 객체 프로퍼티를 저장하고 있는 저장 공간의 주소를 값(&12)으로 가진다.
즉, 객체는 주소값을 이용해 참조한다.

1. 복사의 종류

복사의 종류에는 세 가지가 있다.

참조 복사(reference copy), 객체 복사(object copy), 깊은 복사(deep copy)

이번에도 코드를 통해 세 가지를 알아보자.

// 중첩된 객체 예시
var nestedObject = { name : 'jin', school : { middle : 'haemi', high : 'seoil' }}

// 참조 복사
var referenceCopyObject = nestedObject

// 객체 복사
var shallowCopyObject = shallowCopy(nestedObject)

function shallowCopy(targetObject) {
    var returnObj = {}
    // targetObject를 순회하면서 prop-targetObject[prop](key-value)쌍으로 returnObj에 추가
    for (var prop in targetObject} {
        returnObj[prop] = targetObject[prop] 
    }
      // 새로 만들어진 객체 반환
      return returnObj
}

// 깊은 복사
var deepCopyObject = deepCopy(nestedObject)

function deepCopy(target) {
    var returnValue = {}
    // null의 타입이 object인 버그가 있습니다..
       if (typeof targetObj === 'object' && target !== null) {
          // 만약 타겟이 객체라면 프로퍼티를 재귀 형식으로 호출
        for (var prop in targetObject} {
            returnValue[prop] = deepCopy(target[prop])
        }
    } else {
        // 타겟이 객체가 아니라면 값 반환
        returnValue = target
    }

    return returnObj
}

가정

nestedObject(&20)의 값이 &37이고, &37이 &26(name), &11(school)의 값을 가지고 있다.

&11은 객체를 값으로 가지므로, &11은 &98(middle), &67(high)를 값으로 가진다.

&98은 'haemi'라는 문자열을 값으로 가지고, &67은 'seoil'를 가진다.

복사 결과

referenceCopy의 값

: &37, nestedObject와 똑같은 객체를 가리키는 주소를 값으로 가진다.

 

shallowCopy의 값

: 새로운 객체를 할당했으므로 &20의 값과 &37의 값, &26의 값이 새로운 주소로 할당된다.

  단, &11은 그대로 가지고 있다. 변수에 객체를 새로 할당할 때를 생각하면 이해할 수 있다.

 

변수 deepCopy의 값

: &37, &26(name), &11(school), &98(middle), &67(high)의 값, 즉 모든 주소의 값이 달라진다.

주소를 기준으로 살펴보자

원본 객체 : &20(nestedObject) -> &37 -> &26(name), &11(school) / &11(school) -> &98(middle), &67(high)
참조 복사 : &17(referenceCopyObject) -> &37 -> &26(name), &11(school) / &11(school) -> &98(middle), &67(high)
객체 복사 : &102(shallowCopyObject) -> &42 -> &21(name), &11(school) / &11(school) -> &98(middle), &67(high)
깊은 복사 : &134(deepCopyObject) -> &9 -> &244(name), &342(school) / &342(school) -> &213(middle), &1932(high)

2. 그래서 하고 싶은 말이 뭔데?

간혹, 학습 자료들을 보면 얕은 복사를 설명할때 참조 복사만, 객체 복사만 얕은 복사라고 이야기하는 경우가 있다.

이 경우에서 나는 헷갈렸기 때문에 얕은 복사와 깊은 복사를 나누는 기준을 공유하고자 한다.

 

얕은 복사와 깊은 복사의 영문 뜻은 다음과 같다.

shallow copy : A deep copy means that all of the values of the new variable are copied and disconnected from the original variable
deep copy : A shallow copy means that certain (sub-)values are still connected to the original variable.

 

즉, 복사한 객체가 원래 객체에 연결이 되어있으면 얕은 복사이고 연결이 되어있지 않으면 깊은 복사인 것이다.

이런 측면에서 얕은 복사는 참조 복사와 객체 복사로 이루어졌다고 볼 수 있다.

 

이제 더 이상 얕은 복사(참조/객체)와 깊은 복사를 헷갈리지 말자.

 

참고자료

https://www.freecodecamp.org/news/copying-stuff-in-javascript-how-to-differentiate-between-deep-and-shallow-copies-b6d8c1ef09cd/

 

https://www.youtube.com/watch?v=QFIfI8MIURQ

 

자바스크립트를 잘 다루기 위해 배워야할 내용을 알아보는 시리즈입니다.

읽어주셔서 감사합니다.

 

1편. 자바스크립트 파헤치기

자바스크립트의 동작 원리를 쉽게 파헤쳐 정리하는 시리즈입니다.

 

- 데이터 타입 : https://ladiescheong.tistory.com/45

- 실행 컨텍스트 : https://ladiescheong.tistory.com/46

 

 

+ Recent posts