EtoC

프론트엔드 단기인턴 회고 본문

Project

프론트엔드 단기인턴 회고

게리드 2023. 9. 1. 23:00

2차례 프론트로 개발을 하면서 내가 기업에 나가서 인턴을 할 수 있을까 걱정되었다.

하지만 동기분이 정말 좋은 회사라고 꼭 가보라 하셨고 용기를 내서 인턴경험을 하게되었다.

첫날 회사에 도착하니 회사소개부터 다양한 협업툴과 업무설명을 듣고, 3가지에 선택권을 주셨다.

이때 선택지는 의료인 인증앱만들기, vue와 react를 하나의 레포로 합치기, 에디터 편집기였는데 이상할 정도로 에디터 편집기에 끌렸다.

번쩍 손을 들자 사수분들이 적극성과 의외여서 놀라시면서 박수를 쳐주셨던게 기억난다.

 

0. 구현한 기능

에디터 기능 세분화

이미지만 보면 굉장히 간단한 업무같은데, 실제로 구현을 해보니 우리가 일상에서 당연하다는듯이 사용하던 사소한 기능하나하나에 얼마나 개발자의 생각과 노력이 들어갔는지 알 수 있었다.

 

 


1.  좋았던점

1) 함께해서 좋았다.

업무 배정을 받고 바로 사수님 곁에서 초기세팅을 하였는데, 막힐때 답을 알려주시지않고 약간의 조언과 스스로 해보도록 격려를 해주셨다.

이때 프로젝트 레포에 접근하기위해 ssh key를 생성하여 github과 bitbucket에 연동하면서 팀원가 서로 막히는 부분을 함께 논의하고 재미있게 해결하였는데, 사수님이 사이가 너무좋다며 둘이 함께 작업을 해보기를 권하셨다.

팀원과 함께 작업을 하면서 어떻게 생각했는지 어떻게 문제를 해결했는지를 논의하고 장난도 치고 한달내내함께하면서 즐거웠다.

매주 사수님과 회의를 하면서 밥도먹었는데, 이때마다 좋은 말씀, 재밌는 말씀을 많이해주셔서 좋았다.

 

2)  다양한 경험

모르는것이 있을때 오류와 시도한 방법들 어떻게 되었는지를 정리하여 질문드리면 사수님께서 빠르게 답글을 남겨주시고 어떻게 해야하는지 조언을 해주셨다.

정말 질문드리고 3분내로 읽어보시고 댓글을 달아주셔서 어떤날은 맡은 일을 빠르게 끝내고 오후 2시에 집에간 날도 있었다.

소통이 빠를수록 업무효율이 좋다는 건 진리구나. 다시금 소통의 중요성을 느꼈다. 

사수님도 우리에게 더 도움을 주고싶으시다며 회사의 에디터플러그인을 처음 개발하신 개발자분도 리뷰어로 초대해주셨고, 실장님과 밥먹으며 회의도하고, 기획도 해보았다.

사용자경험과 관련한 작은 기획이였지만 한달이라는 짧은 기간 인턴으로 온 우리에게 기획 할 기회를 주신것에 놀랐다.

반응형웹을 고려하여 디자인팀에서 px로 요청이 들어온것을 em단위로 바꾸고 적용하여 사용자들이 사용하는 기계에따라 폰트사이즈가 바뀌도록 구현하였고 디자인팀에서도 승인이 나서 어떻게 소통하는지도 알 수 있었다. 

 

3) 코드리뷰

GitHub에 PR을 남길때면 사수님과 초기 에디터 개발자분이 코드리뷰를 해주셨다.

이때 분명 곁에 안계신데 옆에 계시는 느낌이들정도로 서로 댓글로 의견을 남기고 보고하며 리뷰를 받았다.

이때 카멜케이스와 스네이크케이스 케밥케이스에대한 논쟁도 일어나고, 들여쓰기의 중요성, 중복된 코드와 주석처리 등 개발자사이의 규칙을 많이 배울수 있었다.


2. 아쉬웠던 점

1) 소통

위에서 소통이 잘되어서 좋았다고 써놓고 아쉬운점으로 소통을 꼽은게 웃길거같다.

이 소통은 첫 일주차의 회사내부의 소통이다.

처음 1주~2차는 제목사이즈를 세분화하고, 본문 버튼을 세분화 하는 업무를 진행하였다.

그런데 구현을 다하고 실장님과 회의를 하다보니 기획이 변경되어 기존에 만들었던것을 다 지워야했었다.

물론  새롭게 배운것이 많았기에 헛된 시도였다는 생각은 하지 않았지만, 사수님께서 다크모드도 만들어보는것을 희망하셨는데

이걸 구현하지못한게 너무 아쉬웠다.

 

2) 나의  나쁜 습관

언제부터 이런 습관이 생긴건지 모르겠는데 예전에 누군가가 나에게 "개발자라면 안될때 자기코드를 거침없이 지우고 새롭게 쓸 줄 알아야한다"고 했었다.

회사의 코드를 분석하고 만들때 어디로 어떻게 연결된건지 이해하지못해서 이것저것 시도를 많이했었다.

그리고 안되면 지우고 다른방식으로 해보고 했는데, 다음날 팀원이 짜온 코드와 비교를 해보니 거의 다했었고 딱 한줄만 더쓰면 되었다는 사실을 알았다.

팀원의 명언이 추가되었다. "복사좀해요!!", "그걸 왜지워요!!"

지울때 지우더라도 내머리가 기억을 하거나 어디에 기록을 해둬야겠다.

 


 

3.  맡은 업무  

ProseMirror를 사용한 에디터 플러그인 고도화 

  • 글자 크기 플러그인 고도화
    • 기존에는 제목, 본문으로 2가지만 설정 가능했던 에디터를 글자크기 드롭다운 버튼을 추가하여 사이즈 다양화를 하였다.

서브모듈인 editior repository에 연결하여 작업하였다.

 


4. 주차별  과정 기록

1주차: ProseMirror 파악 (23/07/31 ~ 23/08/04)

1. ssh key 생성후 github와 bitbucket에 연동.

2. node.js 버전 변경이 필요한 경우를 위해 nvm 설치 및 학습.

3. ProseMirror 파악을 위한 ProseMirror-intro 학습.

2~3주차: 개발 + PR 및 리뷰 기반하여 수정 (23/08/07 ~ 23/08/18)

글자 크기 플러그인 고도화를 위해 적용 되야 할 항목은 아래와 같았다.

  • marks 기반의 글자크기 드롭다운 버튼 생성
  • 제목/ 본문에 따른 상대단위 사용(em)
  • 텍스트에 글자 크기 적용 후 그 안에서 다시 글자 크기 지정할 경우 분리되도록하기
  • 기본 크기, 크기 1 ~5 로 크기 리스트 지정
  • 내부글 복사 붙여넣기 시 font-size 유지/ 외부글 복사 붙여넣기 시 font-size 15px로 통일
  • 글자 크기 드롭다운을 선택한 후 드롭다운 자동 닫기
  • marks 기반의 글자크기 드롭다운 버튼 생성
    • fontSize marks 생성
    //schemas/fontSize.js
    
    import { SCHEMA_STYLE } from "../styles/classNames";
    
    /**
     *
     * @type {import("prosemirror-model").MarkSpec}
     */
    export const fontSizeMarkSpec = {
      attrs: {
        style: {
          default: null,
        },
      },
      inclusive: false,
      toDOM: (node) => [
        "span",
        { style: node.attrs.style, class: SCHEMA_STYLE.marks.font_size },
        0,
      ],
      parseDOM: [
        {
          tag: "span",
        .
            .//생략
            .
    //index.js
    const marks = {
        .
        .//생략
        .
      **font_size: fontSizeMarkSpec,**
        .
        .//생략
        .
    };
    //className.js
    marks: {
        .
            .//생략
            .
        **font_size: EDITOR_CLASS + "__font_size",**
      },
  • 메뉴바 컴포넌트 생성기존에 있는 drop-down 버튼을 사용하지 않고 컴포넌트를 생성한 이유는 EditorMenubar.vue에서 ul과 li를 만들면 코드가길어지는점과 defaultStyle.scsss에서 li의 클래스명별로 중복되는 css가 들어가는점이 유지보수 측면에서 좋지않다고 생각하여 새로운 fontSize 관련 컴포넌트를 생성하였다.에디터 내에서 글자 크기를 선택할 수 있는 드롭다운 메뉴 컴포넌트 생성
    1. template 안에서 liv-for 반복문을 사용하여 글자 크기 옵션 정의하고 글자 크기에 따라 목록 Title 사이즈도 적용됨
    2. props 로 부모 컴포넌트로부터 받아온 값들의 Type 지정
    3. computed 에서 defaultClass 로 계산된 속성을 정의하여 className 동적으로 생성
    4. methods 에서는 이벤트 동작 처리, handleClick 이벤트 함수 같은 경우 유저가 글자크기 선택 시 selectFontSize 이벤트와 함께 선택한 글자크기를 부모 컴포넌트로 전달함과 동시에 closeDropdown 이벤트 실행
// ProseMirrorMenuFontSize.vue
<template>
<ul :class="defaultClass.fontSizeBox" 
@mouseenter="handleMouseEnter" 
@mouseleave="handleMouseLeave" 
style="display: none" :style="{ display: Open ? 'grid' : 'none', }" > 
<li v-for="(fontSize, index) in FontSizes" :class="defaultClass.fontSize"
@click="handleClick" :key="index" :title="fontSize[0]" :data-fontSize="fontSize[1]" :style="{fontSize: fontSize[1]}" >
{{ fontSize[0] }} </li>
</ul>
</template>
<script> 
export default { props: { Open: { type: Boolean, }, Context: { type: String, }, MenubarClassName: { type: String, }, FontSizes: { type: Array, }, }, computed: { defaultClass() { return { fontSizeBox: this.MenubarClassName + "__fontSize-box", fontSize: this.MenubarClassName + "__fontSize-box__fontSize", }; }, }, methods: { handleClick(event) { const fontSize = event.target.dataset.fontsize; if (this.Context === "fontSize") { this.$emit("selectFontSize", { type: "setFontSize", fontSize }); this.$emit("closeDropdown"); } }, handleMouseEnter() { this.$emit("mouseEnter"); }, handleMouseLeave() { this.$emit("mouseLeave"); }, }, }; </script>
// EditorMenubar.vue <!-- 글자크기 버튼 --> 

<prose-mirror-drop-down-button 
@toggleDropDown="toggleDropDown"
:ShowArrowDownIcon="true"
:Icon="menubarAttrs.FontSizeIcon"
:Description="'글자크기'"
:Name="'fontSize'" 
:MenubarClassName="menubarAttrs.className" >
<prose-mirror-menu-fontSize @selectFontSize="emitMetaData" 
:Open="menubarAttrs.openedDropDownName === 'fontSize'" 
:Context="'fontSize'" 
:FontSizes="[['기본 크기', '기본 크기'], ...menubarAttrs.fontSizes]" 
:MenubarClassName="menubarAttrs.className" 
@closeDropdown="closeDropdown" >
</prose-mirror-menu-fontSize> 
</prose-mirror-drop-down-button>
  • 명령 함수 파일 생성(view에 업데이트를 하기 위한 파일)
      //commands/fontSize.js
    
      export const setFontSize = (fontSize) => (state, dispatch) => {
        const tr = state.tr;
        const selection = tr.selection;
        const { from, to } = state.selection;
    
        if (selection instanceof CellSelection) {
          const heading = state.schema.nodes.heading;
          const paragraph = state.schema.nodes.paragraph;
          const tasks = [];
          const allowedNodeTypes = new Set([heading, paragraph]);
    
          selection.forEachCell((cell, pos) => {
            cell.content.forEach((node, offset) => {
              const resolvedNode = state.doc.resolve(pos + offset + 1).nodeAfter;
              if (allowedNodeTypes.has(node.type)) {
                tasks.push({
                  pos: pos + offset + 1,
                  posEnd: pos + offset + 1 + resolvedNode.nodeSize,
                });
              }
            });
          });
    
          if (!tasks.length) return false;
    
          tasks.forEach(job => {
            const {pos, posEnd} = job
    
            fontSize === '기본 크기'
              ? tr.removeMark(pos, posEnd, state.schema.marks.font_size)
              : tr.addMark(pos, posEnd, state.schema.marks.font_size.create({style: `font_size: ${fontSize};`}))
          })
    
          dispatch(tr);
          return true;
        }
    
        if (fontSize === '기본 크기') {
          tr.removeMark(from, to, state.schema.marks.font_size)
    
          return dispatch(tr)
        }
    
        tr.addMark(from, to, state.schema.marks.font_size.create({ style: `font-size: ${fontSize};` }));
    
        dispatch(tr);
        return true;
      };
      //remoteMenu.js (setFontSize 반환 코드)
    
      if (state?.type === "setFontSize") {
                return setFontSize(state.fontSize)(view.state, view.dispatch);
              }
  • 테이블 셀안에서나 일반 텍스트 선택인 경우 tasks 배열 내의 유저 동작에 의해 글자 크기를 설정하거나 제거한다.
// ProseMirrorMenuFontSize.vue <template> <ul :class="defaultClass.fontSizeBox" @mouseenter="handleMouseEnter" @mouseleave="handleMouseLeave" style="display: none" :style="{ display: Open ? 'grid' : 'none', }" > <li v-for="(fontSize, index) in FontSizes" :class="defaultClass.fontSize" @click="handleClick" :key="index" :title="fontSize[0]" :data-fontSize="fontSize[1]" :style="{fontSize: fontSize[1]}" > {{ fontSize[0] }} </li> </ul> </template> <script> export default { props: { Open: { type: Boolean, }, Context: { type: String, }, MenubarClassName: { type: String, }, FontSizes: { type: Array, }, }, computed: { defaultClass() { return { fontSizeBox: this.MenubarClassName + "__fontSize-box", fontSize: this.MenubarClassName + "__fontSize-box__fontSize", }; }, }, methods: { handleClick(event) { const fontSize = event.target.dataset.fontsize; if (this.Context === "fontSize") { this.$emit("selectFontSize", { type: "setFontSize", fontSize }); this.$emit("closeDropdown"); } }, handleMouseEnter() { this.$emit("mouseEnter"); }, handleMouseLeave() { this.$emit("mouseLeave"); }, }, }; </script>
  • 제목/ 본문에 따른 상대단위 사용(em)글자 크기명에 관련된 폰트 사이즈를 em으로 한 이유는 상위요소의 폰트사이즈를 기준으로 사이즈가 변화할 수 있게하여 보다 유연하게 변화시키고 싶어서 사용하였다.
    디자인팀에서 제공받은 사이즈 [13px, 15px, 19px, 22px, 26px]를 기본 사이즈인 15px을 기준으로 어떻게 바뀌는지 아래의 사이트에서 변환하여 할당하였다.
      //styles/fontSizes.js (index 0번은 title, 1번은 적용될 사이즈)
    
      export const fontSizes = [
          ["크기1", "1.73em"],
          ["크기2", "1.47em"],
          ["크기3", "1.27em"],
          ["크기4", "1em"],
          ["크기5", "0.87em"],
        ];
  • PX↔EM 변환 사이트 : https://www.toolo.kr/pxtoem/
  • 텍스트에 글자 크기 적용 후 그 안에서 다시 글자 크기 지정할 경우 분리되도록하기
    • 일반 텍스트
    //schemas/fontSize.js

    toDOM: (node) => [
        "span",
        { style: node.attrs.style, class: MEDISTREAM_SCHEMA_STYLE.marks.font_size },
        0,
      ],
  • 기본 크기, 크기 1 ~5 로 크기 리스트 지정
    • 다른 글자 크기가 지정되어있는 상태에서 [기본 크기] 선택 시 span 태그 제거 되면서 기본(global) font-size인 15px로 변경된다.
      • 일반 텍스트
      • 샐 내 텍스트
      • code
//commands/fontSize.js . . 
//생략 .
export const setFontSize = (fontSize) => (state, dispatch) => {. . //생략 . 
if (!tasks.length) return false; tasks.forEach(job => { const {pos, posEnd} = job 

// 셀안에서 fontSize가 기본크기 일 경우 mark제거 
fontSize === '기본 크기' ? tr.removeMark(pos, posEnd, state.schema.marks.font_size)**
: tr.addMark(pos, posEnd, state.schema.marks.font_size.create({style: `font_size: ${fontSize};`})) }) 
dispatch(tr); return true; }

// 일반 텍스트에서 fontSize가 기본크기 일 경우 mark제거 
if (fontSize === '기본 크기') { 
tr.removeMark(from, to, state.schema.marks.font_size) return dispatch(tr) }
 . . //생략 .
  • 내부글 복사 붙여넣기 시 font-size 유지/ 외부글 복사 붙여넣기 시 font-size 15px로 통일
    • 내부 일반 텍스트 복사 붙여넣기
    • 내부 셀 내 텍스트 복사 붙여넣기
    • 외부 텍스트 복사 붙여 넣기(자세한 결과 사항은 QA TEST 항목 참고)
    • code
복사한 내용이 MEDISTREAM_SCHEMA_STYLE.marks.font_size 키값에 있는 클래스 네임(integration-editor__font_size)이고, font-size의 속성을 가지고 있는 경우 복사한 span태그의 font-size속성을 그대로 가져온다.
그 외에는 false처리하여 모두 기본 사이즈인 15px로 고정
// schemas/fontSize.js parseDOM: 
[ { tag: "span", style: "font-size", getAttrs: dom => { const fontSize = dom.style?.fontSize; const classList = dom.getAttribute('class'); 
if (classList?.includes(MEDISTREAM_SCHEMA_STYLE.marks.font_size) && fontSize) 
{ return { style: `font-size: ${fontSize};` }; } return false; }, }, ],
  • 글자 크기 드롭다운을 선택한 후 드롭다운 자동 닫기
    • code
handleClick 에서 글자 크기가 클릭될 때 이벤트 발생 추가
//ProseMirrorMenuFontSize.vue methods: 
{ handleClick(event) 
{ const fontSize = event.target.dataset.fontsize; if (this.Context === "fontSize") 
{ this.$emit("selectFontSize", { type: "setFontSize", fontSize });
**this.$emit("closeDropdown");** } }, . . //생략 . },
ProseMirrorMenuFontSize 컴포넌트로부터 이벤트를 받아서 드롭다운을 닫는 핸들러 메소드 추가

//EditMenuBar.vue **** <prose-mirror-drop-down-button 
@toggleDropDown="toggleDropDown" :ShowArrowDownIcon="true" :Icon="menubarAttrs.FontSizeIcon" :Description="'글자크기'" :Name="'fontSize'" :MenubarClassName="menubarAttrs.className" > <prose-mirror-menu-fontSize @selectFontSize="emitMetaData" :Open="menubarAttrs.openedDropDownName === 'fontSize'" :Context="'fontSize'" :FontSizes="[['기본 크기', '기본 크기'], ...menubarAttrs.fontSizes]" :MenubarClassName="menubarAttrs.className" **@closeDropdown="closeDropdown"** ></prose-mirror-menu-fontSize> </prose-mirror-drop-down-button> . .//생략 . methods: { . .//생략 . **closeDropdown() { this.menubarAttrs.openedDropDownName = ''; },**

■ 4주차: QA 테스트 및 완료 (23/08/21 ~ 23/08/24)

 

인티그레이션-Editor Plugin QA Test

복사 붙여넣기 / 글자크기 변경 TEST [ QA TEST ] TEST 내용 복사 붙여넣기 / 글자크기 변경 TEST TEST 결과 요약 1. 내부에서 복사 붙여 넣기 하는 경우 <span>태그+ [font-size] + [className] 유지 됨. 2. 외부에서

docs.google.com