일년이 마무리되기까지 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년 큼직큼직한 일정에 대해 회고를 해봤습니다.

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

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

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

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

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

저는 프론트엔드 개발자로 취직하기 위해 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 정의, 한 사이클을 적용한 결과 등에 대해서 이야기를 해보겠습니다.

읽어주셔서 감사합니다.

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

읽어주셔서 감사합니다.

 

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

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

 

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

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

 

 

중급자 빌드업 시리즈의 첫 번째, 자바스크립트 파헤치기의 실행 컨텍스트입니다. 읽어주셔서 감사합니다.


0. 사전 지식

스택 : 먼저 저장된 원소가 나중에 나가는 자료구조

큐 : 먼저 저장된 원소가 먼저 나가는 자료구조

1. 실행 컨텍스트란

실행 컨텍스트란 실행할 코드에 제공할 환경 정보들을 모아놓은 객체입니다.

실행 컨텍스트 수집 → 코드 실행 → 실행 컨텍스트 제거하는 방법으로 환경과 코드의 순서를 보장합니다.

실행 컨텍스트는 variable environment, lexical environment, this binding으로 구성되어 있습니다.

this binding은 나중에 알아볼 예정이므로 lexical environment에 대해 알아봅시다.

2. lexical environment

렉시컬 환경이란 컨텍스트를 구성하는 환경 정보들을 모아둔 환경입니다.

렉시컬 환경은 environment record와 outer-environment reference로 이루어져 있습니다.

3. environment record

environment record에는 현재 컨텍스트와 관련된 식별자 정보들이 저장됩니다.

예를 들어 함수, 매개변수, 변수 식별자 등이 있습니다.

식별자를 수집했어도 코드는 실행되기 전입니다.

즉, 코드가 실행되기 이전에 변수명을 이미 엔진이 알고 있다는 뜻이 됩니다. → 호이스팅

4. outer-environment reference

outer-environment reference에는 현재 호출된 함수가 선언될 당시의 lexical environment를 참조합니다.

예를 들어 A 함수에서 B 함수를 호출하고, B 함수에서 C를 호출할 때

  • C 함수의 outer-environment reference : B 함수의 lexical environment를 참조
  • B 함수의 outer-environment reference : A 함수의 lexical environment를 참조
  • A 함수의 outer-environment reference : 전역의 lexical environment를 참조

outer-environment reference가 호출당하는 함수의 lexical environment를 참조하기 때문에 식별자 유효 범위가 전역까지 참조할 수 있는 것입니다. → 스코프 체인, 전역 변수, 지역 변수

자바스크립트 중급자 빌드업 시리즈의 첫 글, 자바스크립트 작동 원리 파헤치기 1편입니다.

읽어주셔서 감사합니다.

1. 데이터 타입의 종류와 구분법

데이터 타입의 종류

  • 원시형 : number, string, boolean, null, undefined, Symbol 등
  • 참조형 : object(array, function, date, regexp, map, set 등)

데이터 타입 구분 기준

  • 원시형 : 할당이나 연산시 값이 담긴 주소값을 바로 복제
  • 참조형 : 값이 담긴 주소값들로 이루어진 묶음을 가리키는 주솟값을 복제

2. 배경 지식

  • 변수 : 변할 수 있는 수 = 데이터
  • 식별자 : 데이터 식별에 사용되는 이름으로 메모리 주소 값을 가진다 = 변수명, 함수명,

3. 선언과 할당

변수 선언과 데이터 할당

var a = 'abc'

위 코드는 아래와 같은 동작이 이루어집니다.

  • 식별자 a가 가리키는 → 주소 1의 → 값 : undefined
  • 식별자 a가 가리키는 → 주소 2의 → 값 : ‘abc’

여기서 주소 1 ≠ 주소 2이므로 메모리 효율을 위해 할당이 두 번 이루어집니다.

4. 원시형과 참조형 데이터

불변값

// 원시형 데이터
var a = 'abc'
a = a + 'def'

두 번째 줄 코드를 실행할 때 어떤 동작이 이루어질까요?

  1. a가 가리키는 주소의 값이 ‘abc’에서 ‘abcdef’로 변한다
  2. a가 가리키는 새 주소는 ‘abcdef’를 값으로 가지고 있다

답은 2번입니다.

위 동작을 살펴볼 때 원래 a가 가리키고 있던 값 ‘abc’ 자체는 변하지 않습니다.

이를 불변값이라 부릅니다.

가변값

var obj1 = {
	a: 1,
	b: 'bbb'
};

위 참조형 데이터를 변수에 할당할 땐 어떤 동작이 이루어질까요?

  • obj1에 주소 1을 지정합니다
  • 주소 2의 값을 여러 개의 주소로 할당합니다
    • 여러 개의 데이터를 저장하기 위해
  • 여러 개의 주소는 각각 원시형 데이터를 할당합니다
  • obj1의 값에 주소 2를 지정합니다

참조형 데이터는 가변값입니다. 그런데 왜 참조형 데이터는 가변값일까요?

obj1.a = 2;

위 코드가 실행되면 객체 안의 a가 가리키는 주소가 변하고, 변한 주소는 2를 값으로 가지고 있습니다.

즉, a가 가리키는 주소와 값이 변경되었습니다. 그렇다면 객체도 변했을까요?

아닙니다. 새로운 객체가 생성된 것이 아니라 객체 내부의 값만 변경된 것입니다.

변수 복사

원시형과 참조형 데이터의 할당 및 수정 방식을 알아봤습니다.

변수를 복사할 때 어떻게 달라지는지 알아보겠습니다.

먼저 원시형 데이터입니다.

var a = 10;
var b = a;

위에서 변수 a를 선언하고 값을 할당할 때 동작은 다음과 같았습니다.

  • 식별자 a가 가리키는 → 주소 1의 → 값 : undefined
  • 식별자 a가 가리키는 → 주소 2의 → 값 : 10

위에서 변수 a에 다른 값을 할당할 때 동작은 다음과 같았습니다.

  • a가 가리키는 새 주소는 ‘abcdef’를 값으로 가지고 있다

이때, 변수 b를 선언하고 a 값을 할당하면 다음과 같은 방식으로 동작합니다.

  • 식별자 b가 가리키는 주소 3의 값은 undefined
  • 식별자 a가 가리키는 주소 2의 값은 10이므로
  • 주소 4에 값 10을 담고 식별자 b가 가리키는 주소를 주소 4로 변경합니다.

다음은 참조형 데이터입니다.

var obj1 = { c: 10, d: 'ddd' }
var obj2 = obj1;

위에서 변수 obj1를 선언, 할당할 때 동작은 다음과 같았습니다.

  • obj1에 주소 1을 지정합니다
  • 주소 2의 값을 여러 개의 주소로 할당합니다
    • 여러 개의 데이터를 저장하기 위해
  • 여러 개의 주소는 각각 원시형 데이터를 할당합니다
  • obj1의 값에 주소 2를 지정합니다

이제 obj2가 obj1을 복사할 때 동작은 다음과 같습니다.

  • obj2에 주소 3을 지정합니다
  • obj1의 값이 여러 개의 주소를 가리키고 있는 것을 확인합니다
  • 주소 4에 obj1의 값을 저장하고 obj2에 주소 4를 지정합니다

즉, obj1과 obj2는 같은 값을 가리키고(= 참조하는) 있는 것입니다.

아래 예시를 보며 이해해봅시다.

var obj1 = { c: 10, d: 'ddd' }
var obj2 = obj1

obj1.c = 20
console.log(obj2.c) // 20

위 코드를 실행하면 obj2의 c의 값도 20으로 변하는 것을 알 수 있습니다.

obj1과 obj2는 같은 데이터를 참조하고 있기 때문에 한 쪽이 변하면 다른 쪽도 변하는 것을 알 수 있습니다.

5. 얕은 복사와 깊은 복사

위에서 한 변수가 다른 변수의 참조형 데이터를 복사해도 같은 값을 참조하는 것을 알 수 있었습니다.

그렇다면 새로운 값을 참조하도록 만드려면 어떻게 해야 할까요?

답은 간단합니다. 새로운 값을 복사해 할당하면 됩니다.

복사하는 방법은 두 가지가 있습니다.

  1. 얕은 복사 : 객체 바로 아래 단계만 복사하는 방법
  2. 깊은 복사 : 객체 내부의 모든 값을 찾아 복사하는 방법

예시를 보면서 알아봅시다.

var user1 = {
		name: 'Jin',
		urls: {
				github: '<https://github.com/MyungAe>',
				blog: '<https://ladiescheong.tistory.com/>',
		}
}

// 얇은 복사했을 때
user2.name = 'sik' // user1.name = 'Jin'
user2.urls.github = 'a' // user1.urls.github = 'a'

// 깊은 복사했을 때
user2.name = 'sik' // user1.name = 'Jin'
user2.urls.github = 'a' // user1.urls.github = '<https://github.com/MyungAe>'

위 user1 변수를 user2로 얕은 복사를 하면

  1. 원시형 값이 변경 → user1 변수의 값은 변경 X
  2. 참조형 값이 변경 → user1 변수의 값은 변경 O

위 user1 변수를 user2로 깊은 복사를 하면

  1. 원시형 값이 변경 → user1 변수의 값은 변경 X
  2. 참조형 값이 변경 → user1 변수의 값은 변경 X

6. undefined와 null

자바스크립트의 없음을 담당하는 값은 undefined, null 입니다.

다만 이 두 값의 의미가 조금 다릅니다.

undefined

자바스크립트 엔진이 값이 존재하지 않을 때 자동으로 부여하는 값입니다.

변수에 값을 할당하지 않은 채, 선언만 하면 그 변수의 값은 undefined가 됩니다.

var a; // a의 값은 undefined

일반적으로 다음 세 경우가 undefined를 반환합니다.

  1. 값을 대입하지 않은 변수에 접근할 때
  2. 객체 내부에 존재하지 않는 프로퍼티에 접근할 때
  3. return 문이 없거나 호출되지 않는 함수의 실행 결과

null

앞서 소개한 undefined의 한 가지 단점은 사용자가 할당할 수 있다는 점입니다.

엔진이 반환하는 undefined인지, 사용자가 할당한 undefined인지 모를 수 밖에 없습니다.

따라서 이런 문제를 해결하기 위해 비어있음을 나타내고 싶다면 null을 사용해야 합니다.

버그 : null의 타입은 object으로 판정됩니다.

undefined vs null 정리

  • 공통점 : 둘 다 비어있음을 나타내는 값
  • 차이점
    • undefined : 값을 대입하지 않은 변수에 접근하면 엔진이 반환해주는 값
    • null : 사용자가 비어있음을 표현하기 위해 할당해주는 값

의미있는 첫 글을 뭘 쓸지 고민하다,, 성윤님의 추천 주제인 글또 다짐을 쓰기로 했습니당

아무튼 목표와 다짐 시작합니다

머리가 띵

혼자 프론트 공부하던 제게 충격을 가져다 준 사건이 있었습니다. 그건 바로.. 우아한테크코스 5기!

if (guessNumber.length !== this.NUMBER_ARRAY_MAX_LENGTH) {
        throw "input value length isn't correct!";
      }
      const guessNumberArray = guessNumber
        .split("")
        .map((value) => parseInt(value));
      const correctNumberArray = correctNumber
        .split("")
        .map((value) => parseInt(value));
      const scoreboard = { strike: 0, ball: 0 };

      guessNumberArray.forEach((number, index) => {
        this.isStrikeOrBall(number, index, correctNumberArray, scoreboard);
      });

      this.notifyGuessResult(scoreboard);

      if (scoreboard.strike === 3) {
        this.isReplay();
        return;
      }

      this.enterGuessNumber(correctNumber);

이렇게 코드를 짜던 제가, 좋은 코드와 명확한 코드에 대해 고민하게 된 계기가 되었었죠.

지금은 코딩을 모르는 사람이 보더라도 로직을 알 수 있는 코드를 지향하고 있습니다.

readMoving(bridgeGame) {
    MissionUtils.Console.readLine(
      '이동할 칸을 선택해주세요. (위: U, 아래: D)\n',
      input => {
        Validate.isCorrectMove(input);
        const result = Controller.sendUserMoving(input, bridgeGame);
        if (result === GAME_OVER) return this.readGameCommand(bridgeGame);
        if (result === GAME_CLEAR) return;
        this.readMoving(bridgeGame);
      }
    );
  },

이것은 목표인가 다짐인가

그래서 목표가 뭐냐?

  1. 좋은 코드의 예시에서 나만의 기준을 세우는 것
  2. 디자인 패턴에서 배우는 기능 구조
  3. 협업을 위한 코드 컨벤션 - Lint와 Prettier를 중심으로
  4. 기타 프론트엔드 상식

을 2주에 하나씩 작성하고 공유하고자 합니다.

그래서 이게 끝이야?

그렇습니다. 6개월 동안 쓸 주제가 이게 다입니다.

소소하지만 확실한 글쓰기. 지향하는 바입니다.

읽어주셔서 감사합니다?

이 글을 보시는 분들, 안녕하세요 :)

어떤 경로로 들어오셨는지는 모르겠으나 모두 반갑습니다.

 

이 글은 글또 8기 신규 지원을 위해 제 자신은 어떤 사람인지 되돌아본 뒤 해당 내용을 작성한 글입니다.

만약 글또 8기 혹은 뒷 기수 지원을 위해 참고할만한 내용을 찾아 들어오셨다면, 좋은 결과 있으시기를 바라겠습니다.


 

커뮤니케이션과 기획 역량을 갖춘 일에 몰입하는 개발자입니다

 

저는 어렸을 때 컴퓨터에 관심을 가졌습니다.

초, 중학교 시기에 워드프로세서, 한글 및 파워포인트 자격증을 따는 방과 후 학교, 주어진 문제를 보고 인터넷에서 답을 찾는 정보사냥 대회 등에 참여했습니다. 컴퓨터를 전문적으로 배우고 싶어서 컴퓨터공학과 진학을 목표로 각종 진로 체험, 학과 조사 및 C 언어 공부 등을 학교 수업과 병행했습니다.

 

컴퓨터공학과에 진학하고 나서 방황을 조금 했었습니다.

컴퓨터공학과 1학년 때 전공 수업보다 교양 수업들이 더 많았던 것이 문제였을까요, 아니면 '내가 이걸 배워서 평소에 사용하는 프로그램을 만들 수 있을까?'라는 생각이 문제였을까요. 아마 둘 였겠지만, 프로그램 언어를 배우고 실습하고 싶지 않았습니다.

 

한동안 전공 수업보다 밴드 동아리에 더 많이 참가했습니다.

베이스 기타 인원이 적어 비교적 더 많은 곡을 선정하고, 합을 맞추고, 공연 계획 및 스케줄을 조정하는 등의 활동으로 사람들과 많이 대화해야만 했습니다. 이러한 일을 하다 보니 자연스럽게 커뮤니케이션과 기획 능력이 늘어났습니다.

 

지도 교수님과의 상담을 통해 다시 전공 공부를 해보자 마음을 먹었습니다.

평소에 사용하는 프로그램 같은 결과물을 만들고 싶어 한이음 공모전에 참가했습니다. 유저 스토리, 기능 차트, 업무 흐름도와 같은 기획 & 설계 단계부터 프레임워크 등을 이용해 구현하는 단계까지 매일 8시간 이상 참여했습니다. 그러나 좋은 결과물을 내지 못했습니다.

 

저는 왜 좋은 결과물을 내지 못했을까요?

처음 접하는 프레임워크를 많이 이용하다 보니 활용을 잘하지 못했던 것이 가장 큰 원인입니다.

 

그렇다면 어떻게 짧은 시간 안에 배워 활용할 수 있을까요?

이 질문에 대한 답을 찾기 위해 여러 선배 개발자님의 말을 많이 찾아다녔고, 그중에서 답을 찾을 수 있었습니다.

 

제가 찾은 답은 '기본기'였습니다.

지난 2년 동안 밴드 동아리 활동을 하다 보니 CS 지식과 언어 작동원리소홀해질 수밖에 없었습니다. 이는 학습 비용을 높이는 결과를 가져왔던 것이었습니다.

 

이제 제가 부족했던 점과 그 점을 보완하는 방법을 찾았으니 이를 보완하고자 합니다.

글또에 참여하면서 그동안 고민했던 부분들과 해결을 위해 해야 하는 일들을 로 남겨 비슷한 고민을 하는 개발자들에게 도움과 위로를 주고 싶습니다.

+ Recent posts