jungmyungjin / bookreview Goto Github PK
View Code? Open in Web Editor NEW독서록-!
독서록-!
SOLID 원칙은 로버트 마틴이 소프트웨어 디자인을 보다 이해하기쉽고 유연하게 유지 관리 할 수있도록 하는 5가지 설계원칙에 대한 연상 기호다.
주의 : 이러한 원칙을 적용하기위해 노력하는게 좋지만 실용적인 적용인지 항상 의심하고, 이 모든것을 교리로 받아들이지 말아야 한다.
클래스는 단 한가지 이유로 변경되어야 합니다.
각각의 클래스가 프로그램이 제공하는 기능의 한 부분을 책임지도록 하세요. 그 후 책임을 완전히 캡슐화하여 클래스 내부에 숨기세요.
클래스들은 확장에는 열려있어야 하지만 변경에는 닫혀 있어야 합니다.
클래스를 확장할 때 클라이언트 코드를 손상하지 않고 자식 클래스 객체들은 부모 클래스의 객체로 교환할 수 있어야 한다.
자식 클래스의 행동는 부모 클래스의 행동와 계속 호환되어야 한다. 메서드를 오버라이드할 때 기초 동작을 다른 행동으로 교체하지 않고 확장해야 한다.
클라이언트들은 자신이 사용하지 않는 메서드들에 의존하도록 강요해선 안된다.
클라이언트 클래스가 불필요한 행동을 구현할 필요가 없도록 인터페이스를 적당히 작게 만드세요. 그러지 않고 뚱뚱한 인터페이스로 변경한다면 변경된 메서들을 사용하지 않는 클라이언트들까지 망가뜨리게 됩니다.
서로 관련 없는 많은 메서드들을 하나의 인터페이스에 다 집어넣을 필요는 없습니다. 이것을 더 정제된 인터페이스들로 나누세요 필요하다면 그 전부를 단일 클래스에서 구현할 수도 있습니다
주의
상위 계층 클래스들은 하위 계층 클래스들에 의존해서는 안됩니다. 둘 다 추상화에 의존해야 합니다. 추상화는 세부 정보들에 의존해서는 안됩니다. 세부 정보들이 추상화에 의존해야 합니다.
공감 모먼트
'때때로 사람들은 하위 계층 클래스들을 먼저 디자인한 다음 상위 계층 클래스들을 디자인하기 시작합니다. 이것은 새 시스템에서 프로토타입을 개발하기 시작할 때 매우 일반적입니다. 왜냐하면 이 시점에서는 하위 계층 기능들이 구현되지 않았거나 명확하지 않기 때문에 상위 계층에서 무엇이 가능한지조차 확신할 수 없기 때문입니다.'
OOP의 SOLID 원칙은 객체지향 프로그래밍을 할 때에 중요한 지표가 될 것으로 보이며, 객체지향을 한다면 계속 들여다보면서 체크를 해야할 것 같다. 지금은 클래스보단 함수를 많이 사용하고 클래스를 많이 만들거나 복잡한 클래스 로직을 다뤄보지 않아서인지 바로 사용하지는 못할 것 같았다. 사용하게 된다면 최근 본 이미지에디터 영역에서 사용할지도 모르겠다.
모던 리액트 DeepDive 02장 : 리액트 핵심 요소 깊게 살펴보기
<$> <$n>
: 가능<_></_>
: 가능:
를 통해 서로 다른 식별자를 이어주는 것도 하나의 식별자로 취급된다.ex) <foo:bar> </foo/bar>
.
를 통해 서로 다른 식별자를 이어주는것도 하나의 식별자로 취급딘다..
를 여러개 이어서 하는 것도 가능하다.ex) <foo.bar> </foo.bar>
ex) <foo.bar.baz> </foo.bar.baz>
// JSXAttributeName 속성의 키로 값을 넣기
funtion vaild1(){
return <foo.bar foo:bar="baz"> </foo.bar>
}
// JSX Attribute로 JSXElement 값 넣기
function child({attribute}){
return <div>{attribute}</div>
}
export default function App({
return (
<div>
<Child attribute=<div>hello</div> />
</div>
)
})
- 브라우저가 사용자가 요청한 주소를 방문해 HTML 파일을 다운로드한다.
- 브라우저의 렌어링 엔진은 HTML을 파싱 DOM 노드로 구성된 트리(DOM)를 만든다.
- 2번 과정에서 CSS파일을 만나면 해당 CSS 파일도 다운로드한다.
- 브라우저의 렌ㄷ링 엔진은 이 CSS도 파싱해 CSS 노드로 구성된 트리(CSSOM)를 만든다.
- 브라우저는 2번에서 만든 DOM 노드를 순회하는데, 여기서 모든 노드를 방문하는 것이 아니고 사용자 눈에 보이는 노드만 방문한다. 이는 트리를 분석하는 과정을 조금이라도 빠르게 하기 위해서다.
- 5번에서 제외된, 눈에 보이는 노드를 대상으로 해당 노드에 대한 CSSOM 정보를 찾고 여기서 발견한 CSS 스타일 정보를 이 노드에 적용한다.
- 이 DOM 노드에 CSS를 적용하는 과정은 두가지로 나뉜다.
- 레이아웃 : 각 노드가 브라우저 화면의 어느 좌표에 정확히 나타나야 하는지 계산하는 과정.
- 페인팅 : 레이아웃 단계를 거친 노드에 색과 같은 실제 유효한 모습을 그리는 과정
가상DOM의 오해
파이버는 파이버 재조정자(fiber reconciler)가 관리하는데, 이는 앞서 말한 가상 DOM과 실제 DOM을 비교해 변경 사항을 수집하며, 만약 이 둘 사이에 차이가 있으면 변경에 관련된 정보를 가지고 있는 파이버를 기준으로 화면에 렌더링을 요청하는 역할을 한다.
=> 리액트 내부의 파이버와 재조정자가 내부적인 알고리즘을 통해 관리해줌으로써 효율적으로 유지보수하고 관리할 수 있게 된 것이다.
잘못된 memo로 지불해야하는 비용은 props에 대한 얕은 비교가 발생하면서 지불해야 하는 비용이다.
메모이제이션을 위해서는 CPU와 메모리를 사용해 이전 렌더링 결과물을 저장해야하고 리렌더링할 필요가 없다면 이전 결과물을 사용해야한다. 그런데 이 작업은 어디서 들어본 적 있지 않은가? 리액트는 이전 렌더링 결과를 다음 렌더링과 구별하기 위해 저장해둬야한다. 그것이 기본적인 재조정 알고리즘이기 때문이다.
어차피 리액트의 기본적인 알고리즘 때문에 이전 결과물은 어떻게든 저장해두고 있다. 따라서 우리가 memo로 지불해야 하는 비용은 props에 대한 얕은 비교 뿐이다.
반면 memo를 하지 않았을 때 발생할 수 있는 문제
메모이저에션도 어디까지나 비용이 드는 작업이므로 최적화에 대한 비용을 지불할 때에는 신중해야 한다.
PureComponentdㅘ 관련해 리액트 개발자인 댄 아브라모프는 다음과 같이 트윗을 남긴 적 있다
아무 데서나 PureComponent를 쓰지 마세요.
왜 모든 컴포넌트에 memo()를 기본값으로 사용하지 않나요? 그게더 빠르지 않나요?
스스로에게 물어보세요.
왜 lodash의 모든 함수에 memoize()를 사용하지 않나요? 혹시 벤치마크로 성능을 확인해 봐야 하지 않을까요?
그리고 리액트 공식문서에 다음과 같은 내용도 나와 있다
useMemo는 성능 최적화를 위해 사용할 수는 있지만 의미상으로 그것이 보장된다고 생각하지는 마세요. 가까운 미래에 리액트에서는 이전에 메모이제이션된 값들의 일부를 "잊어버리고" 다음 렌더링 시에 그것들을 재계산하는 방향을 택할지도 모르겠습니다.
예를 들면 오프스크린 컴포넌트의 메모리를 해제하는 등이 있을 수 있습니다. useMemo를 사용하지 않고도 작동할 수 있도록 코드를 작성하고 그것을 추가해 성능을 최적화 하세요.
따라서 useMemo를 언제까지고 성능 최적화를 위해 제공해 줄 것이라는 보장은 없다.
리액트를 배우고 있거나 혹은 리액트를 깊이 이해하고 싶고, 이를 위해 시간을 투자할 여유가 있다면?
현업에서 리액트를 사용하고 있거나 실제로 다룰 예정이지만 성능에 대해 깊게 연구해 볼 시간적 여유가 없는 상황이라면?
일단 의심스러운 곳에는 먼저 다 적용해 볼것을 권장한다.
lodash나 간단한 함수의 경우와는 다르게 일반적으로는 props에 대한 얕은 비교를 수행하는 것보다 리액트 컴포넌트의 결과물을 다시 계산하고 실제 DOM까지 비교하는 작업이 무겁고 비싸다.
조금이라도 로직이 들어간 컴포넌트는 메모이제이션이 성능 향상에 도움을 줄 가능성이 크다.
useMemo와 useCallback 또한 마찬가지다. useCallback의 경우는 대부분 다른 컴포넌트의 props로 넘어가는 경우가 많을 것이다. 이 props로 넘어갔을 때 참조 투명성을 유지하기 위해서는 useCallback을 사용하는 것이 좋다.
부모 클래스에서 객체들을 생성할 수 있는 인터페이스를 제공하지만, 자식 클래스들이 생성될 객체들의 유형을 변경할 수 있도록 하는 생성 패턴이다.
팩토리 메서드를 사용하는 코드를 종종 클라이언트 코드라고 부르며, 클라이언트 코드는 다양한 자식 클래스들에서 실제로 반환되는 여러 제품 간의 차이에 대해 알지 못한다. 클라이언트는 모든 객체들이 메서드를 가져야 한다는 사실을 잘 알고있지만, 그 메서드가 정확히 어떻게 작동하는지는 중요하지 않는다.
팩토리 메서드는 항상 새로운 인스턴스들을 생성해야 할 필요가 없다.
팩토리 메서드는 대상 코드가 함께 작동해야 하는 객체들의 정확한 유형들과 의존관계들을 미리 모르는 경우 사용하세요.
TIP : 팩토리 메서드는 제품 생성 코드를 실제로 사용하는 코드와 분리합니다. 그러면 제품 생성자 코드를 나머지 코드와는 동립적으로 확장하기 쉬워집니다.
팩토리 메서드는 당신의 라이브러리 또는 프레임워크의 사용자들에게 내부 컴포넌트들을 확장하는 방법을 제공하고 싶을 때 사용하세요.
팩토리 패턴은 클래스를 추상화 하는 클래스를 만드는 패턴인것 같다. 개념적인 예제코드를 보니 어딘가 연습문제에서 해본것 같기도 하다. 이 패턴을 구현할때 추상화를 하는게 어려울 것 같다. 실제로 도입 후에 추상화 코드를 수정하는 일이 많을지 궁금하다.
그래서 나는, 내가 구글에서 매일 하는 업무와 브레인 스토밍을 비교해보았다. 생각해보니 내가 일을 가장 잘했던 때는, 중요한 과제가 주어졌는데 시간이 충분하지 않았을 때였다.
위험요소가 있는 아이디어가 스프린트에서 성공을 거두었을 때의 보람은 엄청나다. 하지만 스프린트에서 아이디어가 실패했을 때는 실망스러워도 투자 대비 효과가 가장 높다. 단 5일간의 작업으로 치명적 결함을 발견한다면, 능률면에서 최고가 아니겠는가.
스프린트 운영방법
월요일 : 지도 그리기 & 타깃 선택
화요일 : 서로 경합을 벌이는 솔루션들 스케치
수요일 : 가장 좋은 솔루션 결정
목요일 : 진짜같은 프로토타입 제작
금요일 : 표적 고객과 테스트
스프린트 준비하기
스프린트를 시작하기 전에 먼저 적절한 과제를 선택하고 적임자들로 팀을 구성해야 한다. 또한 스프린트를 진행할 시간을 확보하고 장소도 구해야한다.
힘든 과제일 수록 스프린트의 효과가 높아진다.
중대한 이해관계가 걸려 있을 때
시간이 충분하지 않을 때
곤경에 빠졌을 때
어떤 중요한 프로젝트들은 일단 시작하기 어렵다. 진행 도중 힘이 떨어지는 프로젝트들도 있다. 이런 상황에서 스프린트는 부스터 로켓 역할을 할 수 있다. 즉, 중력의 저항을 이기고 추진력을 얻도록 돕는 새로운 문제 해결 방식이 될 수 있다.
먼저 외양을 해결하라.
외양은 중요하다. 제품이나 서비스가 고객과 만나는 지점이 바로 외양이기 때문이다. 인간은 복잡하고 변덕스러운 존재라서 고객이 새로운 솔루션에 어떻게 반응할지 예측하기란 사실상 불가능 하다. 새로운 아이디어가 실패하는 까닭은 대게 고객들이 그 아이디어를 쏙쏙 잘 이해하고 관심을 기울일 것으로 과신했기 때문이다.
적절한 외양이 만들어지면, 그 기반이 되는 시스템이나 기술을 생각해내는 데 도움이 된다. 또 외관에 초점을 맞추면, 실제 구현 작업에 들어가기 전에 신속하게 일을 진행하고 중요한 의문점 들에 대한 답을 찾을 수 있다. 아무리 큰 과제라도 스프린트에서 도움 받을 수 있는 건 이 때문이다.
최근 3주간동안 웹사이트를 만드는 7명의 팀 프로젝트를 진행하였다. 최근에 진행하게 된 프로젝트에서 여러가지 느낀바가 많았는데, 제일 크게 느꼈던 교훈은 '무모하게 도전하고 결과를 이루기 위해 달리자' 였다. 사실 나는 무모하게 일을 벌려놓는다기 보단, ''할 수 있는 만큼만 제대로 하자' 라는 성향이 강했다. 그러나 이번 팀 프로젝트에서 기획할 당시에는 무작위로 팀이 짜진 것이라 팀원들의 개인 능력을 몰라서였는지 현실적인 가능성을 염두하지 않고 무작정 멋진 사이트를 만들기 위한 기획을 담았다. 사실 다른 팀원들의 의견은 어떨지 모르겠지만, 나의 개인적인 마음으론 이게 될까..? 싶었다.
그러나 실제로 모든 팀원이 결과를 위해 전력 질주를 하다보니 결과를 이루게 되었다. 나중에 이에 대해 이야기를 하다보니 스프린트라는 내용에 대해 알게되었다. 내가 겪었던 상황에 대해 공감할 부분과 배울부분이 많을 것 같아. 지금 시점에 읽으면 좋을 것이라 생각하여 읽게 되었다.
OOP(객체지향 프로그래밍)의 4가지 기본 개념, 디자인 패턴
내가 이해한대로 몇가지는 바꾼 내용
코드 재사용
컴포넌트 간의 단단한 결합
, 인터페이스 대신 구상 클래스들에 대한 의존 관계
, 하드 코딩
등 여러가지 요인들이 코드의 유연성을 감소시키고 재사용을 어렵게 하기 때문이다.확장성
공감 모먼트
‘대부분 소프트웨어 개발자들은 이와 같은 상황들을 수십 번 이상 경험했을 것입니다. 이러한 상황들이 발생하는 데는 몇 가지 이유가 있습니다.
첫 번째 이유는 일단 문제를 해결하기 시작하면 문제를 더 잘 이해할 수 있기 때문입니다. 종종 개발자들은 앱의 첫 번째 버전의 개발을 끝마칠 때쯤에 문제의 여러 측면을 훨씬 더 잘 이해하기 때문에 처음부터 다시 개발하고 싶어 할 수 있습니다. 또, 개발자로서의 실력이 향상된 덕분에 작성한 코드가 쓰레기처럼 보일 수도 있습니다.
두 번째 이유는 통제할 수 없는 무언가가 변경되었기 때문입니다. 이는 많은 개발 팀들이 원래 아이디어에서 새로운 아이디어로 선회하는 이유입니다. 예를 들어 온라인 앱에서 플래시에 의존했던 개발자들은 브라우저들이 플래시에 대한 지원을 중단했을 때 코드를 재작성하거나 마이그레이션해야 했습니다.’
‘좋은 소프트웨어 디자인이란 무엇일까요? 그리고 그건 어떻게 측정할까요? 또 이를 달성하기 위해서는 어떤 관행을 따라야 할까요? 아키텍처를 유연하고 안정적이며 이해하기 쉽게 만드는 방법은 무엇일까요?
훌륭한 질문들이나 불행히도 정답은 개발 중인 앱의 유형에 따라 다릅니다. ’
chatGPT에게 해결 방법을 물으면 늘 정답은 상황에 따라 다르다고 한다.
이 책의 초반부분을 읽으면서 우려했던것보단 책이 잘 읽혔고, 디자인 패턴을 왜 읽어야 하는지에 대해 설명이 적혀있어 납득이 갔다. 특히 디자인 패턴을 이해하면 팀원간의 의사소통을 하는데에 사용 되는 공용 언어가 늘어난다는 문장에 동의가 됐다. 객체지향에 대한 내용이 많을 것 같지만, 디자인 패턴에 대해 알게된다면 좀 더 시야가 넓어질 것 같다.
모던 리액트 DeepDive 01장 : 리액트 개발을 위해 꼭 알아야 할 자바스크립트
undefined = 선언이 되었지만 값이 아직 할당되지 않은 값
null = 명시적으로 비어있음을 나타내는 값
===
연산자와 같이 타입이 다르면 false
로 나오는 점은 같으나, Object.is가 좀 더 개발자가 기대하는 방식으로 정확히 비교한다.
-0 === +0 // true
Object.is(-0, +0) // false
Number.NaN === NaN // false
Object.is(Number.NaN, NaN);
NaN === 0 / 0 //false
Object.is(NaN, 0/0) // true
===
와 동일하게 동작한다.리액트 팀에서는 object.is를 기반으로 동등 비교를 하는 shallowEqual
이라는 함수를 만들어 사용한다. ([링크](https://github.com/facebook/react/blob/8e2bde6f2751aa6335f3cef488c05c3ea08e074a/packages/shared/shallowEqual.js))
shallowEqual은 object.is에 객체간 얕은 비교를 한번 더 수행한다. (얕은 비교 : 객체의 첫번째 깊이까지 비교)
리액트에서 얕은 비교까지만 구현한 이유로는 JSX props는 객체이고, props만 일차적으로 비교만 수형하면 되기 때문이다.
이 객체가 연산에 관련된 모든것을 할 수 있는것.
예를들면 자바스크립트의 함수는 일급 객체이다. 자바스크립트의 함수는 인수일수도, 리턴값 일 수도, 변수에 넣을수도 할당도 될 수 있기 때문이다.
함수 선언문은 '함수의 호이스팅'이 발생하여 선언 시점 이전에도 사용이 가능하다.
함수 표현식은 '변수의 호이스팅'이 발생하여 선언 시점 이전엔 undefined로 초기화 된다.
this
이다.화살표 함수 : 상위 스코프의 this
일반 함수 : 전역 객체의 this
메서드 함수 : 객체의 this
생성자 함수 : instance의 this
useEffect(function apiRequest(){
// .. anything..
},[])
물론 위와 같이 콜백함수에 이름을 넣는다 한들 apiRequest()와 같이 접근할 수 있는건 아니다.
function COunter(){
var counter = 0;
return{
increase: function(){
return ++counter
}
decrease: function(){
return --counter
}
counter: function (){
console.log('counter'에 접근)
}
}
}
const key= 'a';
const object = {
a: 1,
b: 1
}
const {[key]:a} = object // a = 1
const {[key]} = object // ERROR !! 변수 네이밍을 하지 않음
// key는 'a' 값을 가지고 있는데, object에서의 'a'를 꺼내오기 위해 [key]를 사용했다.
// 그리고 다시 :a 로 변수 네이밍을 하였다.
any
보단 unkown
을! ... 그리고 추후에 type narrowing을 하자.instanceof
, typeof
로 타입카드, in
(객체의 키 확인)로 key 확인// useState에 제네릭을 적용하기
function Component(){
const [state, setState] = useState<string>('')
}
type HelloType = {
[key : string] : string
}
const hello: Hello = {
hello: 'hello',
hi:hi,
}
hello[hi] // hi
hello['안녕'] // undefined
// record 사용하기
type HelloType = Record<'hello' | 'hi', string>
const hello: HelloType ={
hello : 'hello',
hi : 'hi'
}
// 타입을 이용한 인덱스 시그니처
type HelloType = { [key in 'hello' | 'hi']: string}
// 리터럴 타입으로 암묵적 타입 할당
const hello: Hello ={
hello : 'hello',
hi:'hi'
}
// 다음과 같은 오류가 뜨는 경우
Object.keys(hello).map((key)=>{
// Element implicitly has an 'any' type because expression of type 'string'
// can't be used to index type 'Hello'
// No index signature with a parameter of type 'string' was found on type 'Hello'
const value = hello[key]
return value
})
원인 : Object.keys가 string[]을 반환하는데, 이 string은 hello의 인덱스 키
이기 때문에 접근할 수 없기 때문이다.
해결방법
// 1 - Object.keys(hello)를 as로 타입을 단언하는 방법
(Object.keys(hello) as Array<keyof Hello>).map((key)=>{
const value = hello[key]
return value
})
// 2 - 타입 가드 함수를 만드는 방법, 함수 자체의 타입을 만드는 방법
function keyOf<T extend Object>(obj: T): Array <typeof T>{
return Array.from(Object.keys(obj)) as Array <keyof T>
}
Object.keys(hello).map((key)=>{
const value = hello[key]
return value
})
// 3 - 가져온 key를 단언하는 방법
Object.keys(hello).map(key)=>{
const value = hello[key as keyof Hello]
return value
}
이번 챕터에선 본격적으로 리액트에 들어가기전에 알아야 하는 기본 개념인 자바스크립트와 타입스크립트에 대한 내용을 다루었다. 처음엔, 알던 내용이라 빠르게 읽거나 넘겨도 되지 않을까 싶었다. 하지만 읽다보니 이전에 자바스크립트 딥다이브 책에서 보았으나, 가볍게 읽고 넘어갔던 헷깔렸던 개념. 그렇지만 리액트에서 중요한 개념이 있어 많은 도움이 된 것 같다.
확실히 중요한 개념은 반복학습을 하는 만큼 전에는 이해하지 못했던 것들을 이해할 수 있는 것 같다.
이 전 타입스크립트를 제대로 사용해 보지않고 '러닝 타입스크립트' 책을 빠르게 읽었을때와는 다르게 '한모금' 프로젝트에서 타입스크립트를 사용한 후 이번 내용을 읽어보니, 어려웠던점이나 헷깔렸던 점에 대해 공감이가고 한번 더 짚어줘서 도움이 된 것 같다.
책에는 많은 글자들이 있는데 그 글자 하나하나의 설명이 이해하기 쉬우면서 중요한 내용을 다루어서 꼭꼭 씹어서 읽고싶은 책인것 같다. 천천히 꾸준히 잘 읽어야겠다.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.