frontend 개발중

front-end+maketing

0%

역할을 나누고 그 역할별로 해야되는 일을 한정시키는 것

코드를 짜는 것부터 어떤 일을 할때 항상 생각해볼 지점인 것 같다. 어떤 일을 지시 혹은 한다고 가정하였을 때 그 일의 우선순위를 정하고 그 역할을 분해하여서 좀 더 빨리 할 수 있는 작업으로 나누거나 연관성이 있는 일로 나누는 것을 생각하고 작업한다면 일의 효율은 매우 빠른 속도로 오르는 것을 알게 되었다.그 방식이 최근에 디자인 패턴을 만드는 기초 단계이자 OOP 의 핵심 컨셉이라는 것도 알게 되었다.
factiory

역할모델의 중요성

1
2
3
4
5
6
7
8
9
10
11
12
13
const Binder=class{
#items=new Set;
add(v,_=type(v,BinderItem)){ this.#items.add(v) }
render(viewmodel,_=type(viewmodel,ViewModel)){
this.#items.forEach(item=>{
const vm=type(viewmodel[item.viwmodel],VIewModel).el= item.el;
Object.entries(vm.styles).forEach(([k,v])=>el.style[k]=v):
Object.entries(vm.attributes).forEach(([k,v])=>el[k]=v):
Object.entries(vm.event).forEach(([k,v])=>el["on"+k]=e=>v.call(el,e,viewmodel)):
});
}
};

위와 같은 객체 방식에서 사용하는 하나하나의 스타일 정의가 문제이고 이것을 외부에서 작업이 가능하도록 의존성을 부여하는 방식이 필요하다라는 점에 대한 공부가 좀 더 필요하다는 것을 느꼈다.

알고리즘에 대한 정확한 인식

이진트리를 예시로 든다고 하면 전위, 후위에 대한 정확한 파악 그리고 Doubly linked list(이중 연결 리스트) 와 같은 구조를 스스로 직접 만드는 방식도 완전히 머리에 추가하고 다시 한번 더 공부해야한다는 것을 알게 되었다. 또한 살짝만 알고 있었던 제네릭 알고리즘에 대해서도 코드를 보고 직접 만져보고 직접 쳐보고 경험해봐야 할 것 같다.

개발자가 가져야할 마음가짐

최근에 몇년차 개발자라고 해서 나도 모르게 으쓱한 부분이 있었다고 생각한다.
사실 아는게 아무 것도 없는 사람인데..

뒤에서 출발한다는 것을 인정하자

나이도 있고 개발 경력도 있기는 하지만 사실 개발에서 크게 뛰어난 성과를 이뤄낸 것은 없다. 주도적으로 api를 써서 데이터를 스프레드 시트에 자동화하는 것과 같은 작은 성과정도야 있지만 그거야 회사에서 일하면 당연히 해야할 일이지 칭찬받을 일은 아니다. 다시 하나부터 차근차근 공부를 하고 컴퓨터의 기본 원리부터 알고리즘 그리고 현재 사용되는 라이브러리들의 현황 파악과 원리까지도 차근차근 공부해보자

개발자로서 다시 취업된다면 끊임없이 공부하자

지금도 공부하고 있지만 과거에 머리속에서 쓸데없는 것으로 낭비했던 시간을 상기하면서 많은 것을 공부해보자. 그리고 기초를 중시하자. 컴퓨터는 모는 것을 데이터로 변환할 수 있다. 그 부분을 잊지말자

기록으로서 자주 남기자

현재의 마음가짐도 곧 휘발될 수 있다. 이 당시 내가 가지고 있던 마음가짐을 리마인드하기 위해서 좀 더 많은 글을 써보자. 일기도 좋고 개발 이력도 좋고 안되면 깃에 commit 이라도 남겨두자. 개발할때는 정답이라고 생각하고 개발하지만 지금보면 말도 안되는 코드는 항상 존재한다. 마음가짐도 마찬가지이다.

제네릭이란 타입을 마치 함수의 특정한 성질을 나타내는 변수를 묶거나 지정하는 방식을 의미합니다.

간단하게 예시를 만들어보면 아래와 같다.

1
2
3
4
5
6
7
8
9
fuction gen1<T,U>(msg:T,cmt:U):T{
return msg
}

gen1<string>("kim");
// 값이 두개 지정이 안되어 있어서 컴파일이 안된다.
// 개별 값을 지정한다면 아래와 같다
gen1<string,number>("kim",20)

그렇다면 배열과 튜플일 경우에서의 제네릭을 한번 더 정리해보자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
function gen2<T>(msg:T[]):T{
return msg[0]
}

gen2<string>(['kim','jeong'])
//kim 이 표시됨

function gen3<T,K>(msg:[T,K]):T{
return msg[0]
}

gen3(['kim','jeong'])
//kim 이 표시됨(위와 다르지 않음)
gen3(['kim',5])
//각각의 타입이 잘 정리된 튜플을 파악해서 리턴값을 보여줌


제네릭 클래스는 아래와 같은 방식으로 사용합니다

1
2
3
4
5
6
7
8
9
10
class GenericC<T> {
pi: T;
sum: (x: T, y: T) => T;
}

let math = new GenericMath<number>();
//위와 같은 방식으로 만든다면 개별 sum 함수의 매개변수 지정과 리턴 값이 자
//동적으로 지정되어 편하게 사용가능하게 됩니다.


일단 간단한 부분을 점진적으로 연습하면서 새로운 방식을 하나둘씩 익히는 방향으로 진행한다면 좀 더 좋아보인다.

파이널 프로젝트가 완료되고 전체적으로 조금 들뜬 측면도 있었고 이번주에 너무 팩트폭력을 많이 들어서 조금 피곤한 측면이 있지만 내가 발전하는 과정이라고 생각하고 조금 마음가짐을 다시 잡는다는 측면으로
파이널 프로젝트를 정리해보려고 한다.

파이널프로젝트 기업연계 작업 github

  1. 소감

전체적으로 부족함이 많았던 것이 사실이다. 초기에 브랜치 전략을 정리하지 못한 점, 컨플릭트도 자주 나왔었고 git 관련해서도 좀 더 섬세함이 필요한 것을 확인했다. 홀로 잘하는 것이 정답이 아니고 각자 아는 부분을 통합하고 그것을 전략화하는 것이 중요하다고 본다.

  1. 향후 코드

초기에 너무나도 빠른 시기에 개발한 측면이 있어서 코드가 이상하게 정리된 부분이 있어서 하나씩 정리중이다. 개별 react component안에서 비동기 api 호출을 자제하는 것은 기본이기에 최대한 axios는 리덕스에서 thunk 방식을 통해서 정리하여 dispatch 하는 방향으로 정리중이고 부분적으로 알아보기 힘든 부분이 너무 많기에 typescript로 마이그레이션도 실행중이다. 개별 api에서 받아오는 데이터를 좀 더 불변적으로 정리하여 error를 미연에 방지하고 cypress 를 통해서 e2e 테스트를 하면서 기초적인 앱이라는 것에 필수적인 것을 체크하고 있다.

  1. 그렇다고 해도 완성이란 없다

코드에 완성은 존재하지 않는다. 이 프로젝트를 가능한 최대로 리펙토링 하면서 공부를 해보려고 한다. 방식은 틀릴지도 모르지만 접근 자체는 나쁘지않다고 생각한다.

  1. 추가 1

이후 typescript 로 마이그레이션 작업을 하였으며 , 그 뒤에 코드의 중복이나 네이밍이 이상하다고 생각하는 부분을 전체적으로 수정하였다. 물론 전부 수정은 못 하였지만 공부에 많은 도움이 되었다고 생각한다. -2022.12.03

  1. 추가 2

2023년이 되어서 다시 살펴 본 결과 이 사이트를 유지 보수 한다는 것은 매우 힘들다는 것을 깨달아서 초기 개발 시기에 설계가 얼마나 더욱 중요한지 깨닫게 되었다. 11월말부터 작업한 monorepo 작업은 매우 흥미 있는 작업이었지만 yarn breey 로 맞춰서 작업하는 것도 다른 의미로서 공수가 필요하다라는 것을 알게 되었으며 , 어떤 ui 를 공용으로 쓸지 어떤 라이브러리를 공통으로 쓸지에 대해서도 경험이 부족해서 좀 더 배워야겠다는 생각이 들었다. -2022.01.01

interface 정리 2

생각보다 interface의 기능이 조금 길어 두개로 나누어보았다. 그 전 내용은 링크 참조
interface1

1. function interface

함수에서 매개변수나 함수형 interface를 사용시 여러 문제 사항이 있는데 그 것을 정리해보려고 한다.
간략하게 코드를 만들어보자

1
2
3
4
5
6
7
8
9
10
interface Person{
(name:string,age?:number):void;
}
//함수형 interface

const localData:Person=function(name:string,age:number){
console.log(`hello my name is ${name}`);
}


위에서의 코드에서 문제는 무엇일까? name:string,age:number라는 곳에서 문제를 찾아볼 수 있다. localData는 결국 Person이라는 interface를 참조하였고 그 방식으로 실행하는 것인데 interface에서 age:number의 방식은 옵셔널 프로퍼티 방식이다. 값이 다르니 결국 실행되지 않으며 위와 같은 방식으로 문제를 접근한다면 좀 더 구조가 잘짜여진 코드를 만들 수 있을까 하는 생각이 든다.

2. Readonly Interface

Readonly라는 특성은 간단하다. 값은 지정가능하지만 그 값을 변경하지 못하도록 설정하는 것이다.

1
2
3
4
5
6
7
interface Person{
name:string;
age?:number;
Readonly id:number
}
//id 값은 변경불가능

3. intersection

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
interface ErrorHandling{
isSuccess:boolean;
isError?:{msg:string}

}

interface UserData{
name:string;
age?:number;
}

type UserDataCheckResponseType=UserData&ErrorHandling
// type alias

interface IsUserDataCheckResponse extends UserData,ErrorHandling{}
// 다중 상속

intersection 방식은 공부 할 부분이 제법 되는 부분 같다. 다중 상속과 interface의 연계등 좀 더 많은 예시를 보면서 손과 눈에 익혀보도록 해보려고 계획을 해봐야겠다.

3. Merging interface

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface UserData{
name:string;
age?:number;

}

interface UserData{
id:number;
}

let data:UserData;
// id,name,age 의 사용이 다되도록 Merging이 자동으로 된다
// type alias 는 Merging 사용이 불가능하다.

interface 정리

한번 더 정리한다는 생각으로 다시 typescript를 정리해보려고 한다. 먼저 interface 사용방식만 간략하게 정리해보려고 한다.

1. Optional property

1
2
3
4
5
6
7
8
9
interface User{
id:number;
name:string;
age:number;
gender?:"male"|"female";
// 1번 Optional property
[index:string]:any;
// 2번 Optional property
}

1번 Optional property는 간략하게 값이 있을수도 있고 없을 수도 있다는 뜻이다. 그 값이 필수가 아니라는 것이기에 옵션이라는 의미에 매우 적합하다. 사용예시는 간단하다

1
2
3
4
5
6
7
8
9
10
const kim:User={
id:1, name:"kim gi tae",age:33
}
// Optional property noting

const kim2:User={
id:1, name:"kim gi tae",age:33,skills:["game","painting"]
}


한사람의 데이터를 정의할때 위와 같은 User interface를 지정하고 그 데이터에서 반드시 필요한 id,name,age는 정의하지만 다른 데이터는 정의할 필요가 없다. 그것이 Optional property 이다.

2번 Optional property는 필요한 값을 자신이 편하게 만들수 있다는 의미의 Optional property라고 할 수 있다.
사용예시 같은 경우는 위의 예시와 같이 그 데이터에서 필요한 skills과 같은 값을 지정하고 내부 값은 string으로 지정하겠다라는 옵션적인 선언 방식이다.

2. fuction in interface

interface에서는 간단히 함수도 지정할수 있다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
interface User{
id:number;
name:string;
age:number;
gender?:"male"|"female";
[index:string]:any;
getData():void;
}

const kim:User={
id:1,
name:"kim gi tae",
age:33,
getData():void{
console.log(`안녕하세요!${this.name}입니다`)
}
}

void라는 방식으로 지정한다면 값을 return 하지 않고 실행만하는 방식으로 지정한다는 뜻이다. 위의 예시의 kim 변수와 같이 말이다.
재미있는 건 getData()의 내부 값에서 this의 값도 interface로 지정이 가능하다는 것이다.
getData(this:User)라고 지정하는 것으로 this는 User의 규칙을 맞춰서 쓰는 것이 가능해진다라는 것이다.

3. class implements interface

아까전 만들어둔 interface를 통해서 class를 만들수도 있다.
implements라는 방식을 통해서 만드는 것인데 매우 간단하게 class 생성이 가능해진다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
interface User{
id:number;
name:string;
age:number;
gender?:"male"|"female";
[index:string]:any;
getData():void;
}

class UserData implements User{
id:number;
name:string;
age:number;
gender?:"male"|"female";
constructor(name:string){
this.name=name
}
getData():void{
console.log(`안녕하세요${this.name} `)
}

}

interface에 담겨진 데이터를 매우 쉽게 재규정할 수 있으며 좀 더 확실한 규칙으로 객체를 만들기 쉽다고 느껴졌다.

4. interface extends interface

interface의 상속도 매우 간단하다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
interface User{
id:number;
name:string;
age:number;
gender?:"male"|"female";
[index:string]:any;
getData():void;
}

interface gameUser extends User{
char:string;

}

전체적인 상속을 통해서 필요한 데이터를 추가하고 개별적으로 사용가능하니 재사용성도 무척 좋다고 생각된다.

간단하게 우리가 웹이란 곳을 이용해서 일을 한다는 시점에 웹에서 일어나는 문제중 중요한 지점 즉 트래픽의 중요성을 정리해보았다.

트래픽(traffic)

서버에 사람이 많아지면 traffic 높아지고 그 결과로 server의 과부하로 인해 server컴퓨터가 죽어버린다.
그렇기에 우리는 항시 traffic을 파악하고 모니터링 할 수 있어야한다.

가장 기초적인 모니터링은 서버 가용성의 파악이다

서버 가용성

기초적인 단계로 실험해볼 수 있는 개인용 서버로서 보통 vercel이나 aws를 통해 서버를 만드는데 그 경우 프론트엔드도 바로 서버의 가용성을 체크하는 것은 문제없이 가능하다.
traffic은 서버의 사람의 유동성만의 문제는 아니다. js를 어떻게 사용하는지 혹은 이미지 파일을 어떤 방식으로 쓰냐에 따라서 트래픽을 급격하게 낮출수도 있으며 그것이 프론트엔드 기술의 핵심이라고 할 수 있다.
DB와 API를 어떤 방식으로 쓰는지 정도도 프론트엔드가 파악할 일중 하나일 수 있다. DB 서버가 죽었는지 안죽었지정도도 프론트엔드가 파악해야 일을 원활하게 할 수 있다.

서버 가용성과 같은 문제를 공부하기 위한 방법

직접 rest api 서버와 aws서버를 하나 만들어두고 테스트를 해보려고 생각중이다. 현재 aws에 db서버는 완성되어있으며
rest api 서버는 간단하게 nextjs를 통해서 만들어보려고 준비중이다.

미니프로젝트 작성을 완성하였다.

요즘 정신이 없어서 블로그 작성을 좀 미뤘는데 간단하게나마 미니프로젝트 소회를 정리해보려고 한다.

배운것

  1. 변수명의 중요성 (못한점)

변수명의 중요성 : 팀프로젝트로 시작해서 어느정도 작업이 시작되고 나서 서로간의 규칙을 지정하지않은 것이 결국 중반이 가니 조금씩 문제가 되었다. 어떤 것을 지칭하는지 잘 알수 없는 변수명이 계속 RP되고 서로간도 알아볼 수 없는 파일 하나씩 생기는 것을 직접적으로 경험하게 되었다. 그렇기에 다시 한번 팀원분들께 변수명을 같이 정리해보자고 이야기를 하게 되었다.

  1. 폴더 구분의 중요성 (잘한점)

전체적으로 기능부분과 redux 부분 그리고 view 로 관리를 시작했는데 생각보다 이렇게 나누는 것이 중요한 것을 다시한번 배웠다. 기본적인 MVC구조라고 생각하고 관리하니 다른 팀원도 크게 불편함이 없었다.

  1. 상태관리의 어려움

데이터 흐름을 단방향으로 흐르게 하는 상태관리 툴 redux를 사용하긴 했지만 그 관리 방식을 크게 다뤄보지 못해 어려 시행착오가 많았다. 순서와 병합 useSelecter 의 데이터 관리 방식 등 좀 더 공부할 점이 많다는 것을 배운 미니 프로젝트가 아니었나 생각해본다.

  1. 웹접근성에 대한 사고

전체적으로 프로젝트 기본골격에만 신경을 쓴다고 span에 클릭을 넣거나 a 링크 관리나 필요없는 html 코드를 남발한 구석이 있어 수정을 하였다. 알고 있는 부분이었지만 신경을 좀 못쓴것을 반성하는 계기가 되었다.
다시 한번더 [A11Y]https://developer.mozilla.org/en-US/docs/Web/Accessibility 를 살펴볼 계기가 되었다.

회고

  1. 유닛 테스트를 만들고 미니프로젝트를 해보자

관리적인 측면도 있고 웹개발 선행 단계에서 좀 더 어디가 문제인지 바로 파악이 가능하게 설계할 수 있어보인다. 간단하게 jest 를 사용해보는 것이 좋아보인다.

  1. 초기 변수명 선언에 규칙을 만들고 제작하자

변수명 선언할때 카멜케이스를 쓸지 혹은 어퍼케이스를 쓸지 혹은 변수명의 길이를 제약할지 등 기초적인 부분은 초기에 팀원과 같이 정해두고 개발하는 것이 중요할 것이라고 생각이 든다.

  1. 우선순위를 다시 한번 생각하고 개발하자

우선순위 없이 개발하면 개발 단계에서 무수히 많은 문제가 발견되어 다시 한번 더 고치게 되는 문제를 겪게 된다. 이부분도 공부를 하게 되어 좀 더 체계적인 방식을 공부해볼 생각이 들었다.

Symbol.iterator 의 의미

이전 내용 참조

이전 내용에서 javascript의 for of는 과거의 방식과는 다른 방식으로 사용되고 있다는 것까지 알게되었다.

그렇다면 이 Symbol.iterator 다른 예시와 구조를 보면서 만든 사람들의 사고를 떠올려보자

먼저 내부 구조를 살펴보자

아까전에 array에 Symbol.iterator가 있는 것을 알게 되었다.
그럼 그 Symbol.iterator의 내부구조를 console.log로 확인해보자

1
2
3
4
5
6
let list=[1,2,3,4]
const a=list[Symbol.iterator]
console.log(a)
// 결과값 ƒ values() { [native code] }
````
배열의 Symbol.iterator를 가져오면 그값은 함수가 되는 것을 알게 되었다 그렇다면 함수를 실행해보자

const a=listSymbol.iterator
// 결과값 Array Iterator {}

list의 Symbol.iterator라는 것을 실행시키니 Array lterator가 등장한다. 그리고 그 안에는 
1
2
3
4
5
6
7
Array Iterator {}
[[Prototype]]: Array Iterator
next: ƒ next()
Symbol(Symbol.toStringTag): "Array Iterator"
[[Prototype]]: Object
Symbol(Symbol.iterator): ƒ [Symbol.iterator]()
[[Prototype]]: Object
next라는 함수와 prototype값이 존재한다. ## next라는 함수 next와 순회는 매우 적절한 매치가 아닐까 한다.그렇다면 다시한번더 next를 실행해보자
1
2
3
let list=[1,2,3,4]
const a=list[Symbol.iterator]().next()
{value: 1, done: false}
value 값은 매우 익숙한 값이 나왔다. 이방식이 현재의 ES6 순회의 근간이자 하나의 추상화 방식이다라는 것을 알게되었다. 그렇다면 done은 무엇일까
1
2
3
4
5
6
7
8
9
10
11
12
13
let list=[1,2,3,4]
let a=list[Symbol.iterator]()
undefined
a.next()
{value: 1, done: false}
a.next()
{value: 2, done: false}
a.next()
{value: 3, done: false}
a.next()
{value: 4, done: false}
a.next()
{value: undefined, done: true}
next를 계속 실행하면 계속 value는 순회하고 그 값이 없으면 done은 ture가 되는 방식이라는 것을 알수 있다. ## 또다른 예시
1
2
3
4
5
6
7
const set=new Set([1,2,3])
for(const a of set) console.log(a)
//값이 나타난다는 것은 Set 인스턴스에도 Symbol.iterator가 존재한다는 뜻이다

const map=new Map([['a',1],['b',2],'c',2])
for(const a of set) console.log(a)
//값이 나타난다는 것은 Map 인스턴스에도 Symbol.iterator가 존재한다는 뜻이다
매우 직관적이고 현재의 javascript의 비밀을 알게 된 것 같아서 매우 즐겁다. 이번주는 이 방식을 통해서 좀 더 많은 사용예시를 써볼까한다.

Symbol.iterator

공부할때 간간히 까먹기는 했는데 전체적으로 한번 정리가 필요한 시점이라 정리를 해보려고 한다.

현재 Symbol.iterator는 어떻게 사용되는가?

기존에 사용하던 for문에서 우리는 명령에 가까운 코딩을 해왔었다.
그렇다면 현재 ES6에서의 javascript 는 어떻게 변하였을까

1
2
3
4
5
6
7
8
9
10
11
12
//과거 ES5
var list =[1,2,3,4,5]
for(var i=0;i<list.length;i++){
list[i]
}

//현재 ES6
let list =[1,2,3,4,5]
for(const x of list){
x
}

이와 같은 변화의 기본 이유가 어떤 것이고 왜 이렇게 된 것인지
유인동 강사님의 강의를 듣고 매우 많이 정리가 되었다.
바로 위에서 말한 Symbol.iterator 라는 방식을 javascript는 채택 하고 쓰고 있던 것이었다.

  • Symbol.iterator라는 Symbol
    “심볼(symbol)”은 데이터 형식과 심볼 데이터 형식의 인스턴스를 생성하는 클래스와 유사한(class-like) “Symbol”이다라는 것이 현재 javascript 공식 문서의 설명이다.

우리는 한걸음 더 나아갔다. Symbol을 통해서 그렇다면 class와 비슷하게 추상화를 할 것이다라는 것을 추론해볼수 있다.

  • iterator라는 반복기
    영어 자체의 의미가 반복기(iterator)라는 뜻이다. 그렇다면
    좀 더 명확해졌다.

추상화를 통한 반복

Symbol.iterator는 결국 추상화를 위한 반복이다
약간의 예시를 보자

1
2
3
4
5
6
7
const arr=[1,2,3]
arr[Symbol.iterator]=null
// 배열의 Symbol.iterator 값을 초기화해보자

for(const x of arr) console.log(x)
//

답은 어떻게 되었을까?
역시 아무런 답이 나오지 않는다. TypeError arr is not iterable
of 의 순회는 과거의 방식과 달라진 것을 명확하게 알수 있었다.