그동안 서버만 하다가 회사 프로젝트로 다노 매거진을 개편하는 업무를
진행하게 되었다.

관련 글 : daeguowl.tistory.com/185

 

다노 매거진 개편 프로젝트를 완료하며...

올 한해 여러가지 프로젝트를 진행했지만, 정말 나의 피, 땀, 눈물이 들어간 프로젝트를 마무리하며 회고글을 적어보고자 한다. 사건의 발단 : 현재 다노에서는 매주 or 2주 단위로 1on1 이라는 것

daeguowl.tistory.com

처음 사용해보는 React로 웹을 개발하고 나니 SPA(single page application)라는 말을 듣게 되었다.

즉 한 페이지에서 각각의 컴포넌트들만 랜더링 되면서 사용된다는 것인데,
처음에는 이게 무슨 말인지도 몰랐다.

여러 페이지를 이동하는 것 같은데, 왜 싱글 페이지라고 할까...??

즉 react의 경우 build 된 이후의 파일을 보면 body 부분이
<body></body>로 텅 비어있고, js로 이 body부분을 변경해 가면서
rendering 된다는 것이다.

다만 이렇게 되면 우리의 사이트를 크롤링해가는 봇들이,
우리 사이트를 빈사이트로 인식하게 된다.

매우 큰 이슈다...

여러 부분의 단점이 있지만 일단 크게 와닿는 부분은 
해당 페이지가 rendering 되기 전의 정보를 가져가다 보니,
공유하기 등을 하였을 때 해당 페이지의 링크만 공유되는 불상사가 일어났다.

정말 간단하게는 대표 이미지와 description을 정해놓고 meta tag에 넣어주면 된다.

간단하게는 이렇게 대표 이미지와 글을 넣어 놓을 수 있다.

사실 이렇게만 해도 대부분의 회사에서는 해결이 될텐데, 문제는 특정 상품의 링크를 공유했을 때
해당 부분이 나왔으면 좋겠다는 것이다.(제품별로)

사실 다노샵처럼 여러 제품이 있는 경우가 아니라면 
각각의 특정 페이지별로 SSR하는 것은 이미 잘 만들어진 러이브러리들이 많다.

react-helmet이라는 라이브러리인데, 이정도의 SEO가 필요하다면,
아래 글을 참고 하면 된다.

velog.io/@byseop/SPA%EC%97%90%EC%84%9C-%EC%84%9C%EB%B2%84%EC%82%AC%EC%9D%B4%EB%93%9C-%EB%A0%8C%EB%8D%94%EB%A7%81%EC%9D%84-%EA%B5%AC%EC%B6%95%ED%95%98%EC%A7%80-%EC%95%8A%EA%B3%A0-SEO-%EC%B5%9C%EC%A0%81%ED%99%94%ED%95%98%EA%B8%B0

 

SPA에서 서버사이드 렌더링을 구축하지 않고 SEO 최적화하기

얼마 전 create-react-app 기반의 SPA 프로젝트에서 빠른시간내에 SEO를 적용해야 하는 일이 있었습니다. 제가 아는것은 SPA의 SEO는 next.js 혹은 gatsby 를 이용하여 개발하거나, 직접 서버사이드 렌더링(Se

velog.io


아무튼 내가 하고 싶은 것은 각각의 제품별로 SEO를 진행하고 싶은 것이었다.
(일단 여기서 다룰 것은 링크를 공유했을 때 각각의 제품에 맞는 제품명과 사진을 가져가서 보여주는 것이었다.)

확인해보니 쿠팡과 gmarket은 잘 구현되어 있다.

다노의 경우 위의 대표링크를 공유했을 때처럼 제품을 공유해도 SSR이 되어 있지 않아서,
default로 meta tag에 설정해놓은 이미지와 설명이 나오고 있었다.

사실 여러가지 방법들이 있겠지만, 
프론트개발자분들은 너무 리소스가 없으셨고,
서버단에서 이 문제라도 해결할 수 있는 방법이 없을까 모색하였다.

일단 크롤러 봇이 프론트의 build된 코드에 접근해 버리는 순간
어떤 방법을 써도 SSR을 하는 것이 어려웠다.

그래서 프론트의 build된 코드로 접근하기 전에 붙어 있는 nginx에서
봇인지를 판단해서 우리가 만들어 놓은 페이지로 redirect를 하면 되지 않을까?라는 
아이디어를 내놓게 되었다.

전체적인 그린 그림은 아래와 같다.

검정색은 일반적인 흐림이라면, 빨간색은 봇이 들어올 때의 움직임을 표현하였다.
일단 봇이 user-agent를 잡아서 봇인 경우, build된 코드로 넘기지 않고 서버의 새로운 api 로 redirect 시키는 것이다.

그리고 그 api는 서버에서 원하는 meta tag를 넣은 templates를 rendering 시켜주자고 
계획을 세웠다.

이렇게 게획을 세우고 나니, 한번 해봐도 될 것 같다는 생각이 들어 바로 진행하였다.

먼저 django에 rendering 해줄 수 있는 templates를 하나 만들었다.
(현재 다노에서는 python과 django로 서버를 구성하고 있다.)

간단하게 표현하면 아래와 같다.

# product_info로 rendering할 때 data를 넘겨줄 예정

<!DOCTYPE html>
<html lang="en">
    <head>
        <meta charset="UTF-8">
	<meta property="og:title" content="{{ product_info.title }}"/>
        <meta property="og:image" content="{{ product_info.image }}"/>
        <meta property="og:description" content="{{ product_info.description }}"/>
        <title>Title</title>
    </head>
    <body>
        
    </body>
</html>


(회사마다 어떤 걸 SEO하고 싶은지는 다를 수 있으니 가장 기본에 충실한 것만 여기서 표현하고자 한다.)

이렇게 rendering 해줄 수 있는 templates를 하나 만들고 이제 해당 templates를 rendering 해줄 수 있는 
view를 만들었다. 이것도 매우 간단하다.

class ProductSeoView(View):

    def get(self, request, **kwargs):

        product_id = int(request.GET.get('product_no', -1))
        
        # 각자 SEO하고자 하는 코드를 적으면 된다. 아래코드는 예시로 표현하였다.

        product = Product.objects.get(id=product_id)
        title = product.title
        description = product.description
        image = product.image
        url = product.url

	product_info = {
            'title': title,
            'description': description,
            'image': image,
            'url': url,
        }

        return render(request, 'seoproduct.html', {'product_info': product_info})

(해당 코드는 예시로 적은 코드이다)

view 역시 굉장히 간단하다. 
제품 번호를 받아서 거기에 맞는 제품 정보를 가지고 와서, product_info에 넣고, 해당 템플릿을 랜더링 시켜주는 것이다.

그럼 해당 view로 요청이 왔을 때 아까 위해서 만든 템플릿이 해당 product_info 정보를 받아서 랜더링 되게 된다.

이제 해당 view를 띄어줄 수 있도록 url만 하나 뚫어주면 된다.
기존 요청 오는 api아래에 seo라는 api 하나만 더 뚫어주면 된다.

# 기존 product view
re_path(r'^/product?$', ProductView.as_view(), name='product_view'),

# product seo를 위한 view
re_path(r'^seo/product?$', ProductSeoView.as_view(), name='product_seo_view'),


이렇게 되면 서버쪽은 모두 준비가 되었다.

그럼 runserver를 돌린 뒤에 해당 api로 요청을 보내보면 빈페이지가 나와 있어야 한다.
그리고 추가적으로 소스코드를 보면 meta tag에 해당 내용이 담겨 있어야 한다.

이것만 확인 되었으면 이제는 프론트 nginx의 설정을 건드려야 한다.

프론트 서버의 nginx conf파일을 변경하자.
회사마다 모두 다를 것이라고 생각하기 때문에 포인트만 잡고자 한다.

여기서 하고자 하는 것은 바로 카카오톡 봇을 파악해서,
바로 위의 SEO를 위한 서버 URL로 redirect 시키는 것이다.

프론트 서버의 nignx의 location 설정을 변경시켜주면 된다.

location /product { 
	# 여기는 잡고자 하는 bot의 user_agent를 모두 넣으면 된다.
	# 지금 여기서는 kakao talk만을 기준으로 한다.

    if ($http_user_agent ~* "kakaotalk-scrap") { 
      	 rewrite ^/(.*)$ [api_server_url]/seo/$1 permanent;
    }
    
}

=> 프론트의 build된 코드를 서빙하는 것이 아니라 봇일 경우 api_server의 nginx로 seo라는 경로를 앞에 추가하여 
보내도록 하였다.

이렇게 한 뒤에는
nginx -t
nginx -s reload를 통해서 nignx를 다시 load시켜준다.

이제 테스트를 진행해보자!!

카카오톡에 seo를 진행하였던 링크를 복사해서 붙여 넣으면 된다.
그러면 카카오봇이 해당 사이트의 정보를 가지고 오기 위해 접근할 것이다.
(혹시라도 있을 캐시를 삭제해주는 것이 좋다. 카카오 dev에서 삭제가 가능하다)

그리고 프론트 nignx의 로그를 보면

GET /product?product=486 HTTP/1.1" 301 194 "-" "facebookexternalhit/1.1; kakaotalk-scrap/1.0;

오 get요청이 왔고 301로 제대로 redirect 되었다는 표시가 나온다!

이제 서버쪽 nignx의 로그를 보면

seo/product/?product_no=526 HTTP/1.1" 200 "https://danoshop.net/product/?product_no=526 "facebookexternalhit/1.1; kakaotalk-scrap/1.0

기존에 danoshop 요청 url이 seo라는 url로 붙어서 다시 들어온 것을 볼 수 있다.

그래서 그 결과는 과연 어떻게 되었을까?

기존에는

이렇게 상품을 공유해도 default 이미지가 나오던 것이
각각의 상품에 맞게 잘 나온다!!

이렇게 이쁘게 잘 되어 나온다!


이것으로 1차 목표하였던 카카오톡에 개별 링크를 공유했을 때
default meta tag가 아닌 각각의 사진과 text가 나오도록 작업을 진행하였다.
프론트 개발자분들의 리소스가 부족한 상황에서
서버 개발자인 내가 할 수 있는 부분에서 개선을 해보았다.

다만 작업을 하면서 추가적으로 고려해야 하는 부분도 발견하였다.
바로

[높은 페이지랭크를 가진 URL은 검색결과에서 더 상위에 노출 것입니다. 따라서 높은 페이지랭크를 가진 URL을 구입하여 컨텐트만 광고페이지로 이동시키는 부적절한 사례가 증가하고 있습니다. 이 때문에 구글은 302를 자주 사용하거나 부적절하게 사용할 경우 기존 사이트랭크에 상당한 패널티를 부여합니다.]

출처: https://nsinc.tistory.com/168 [NakedStrength]

의 글이다. 봇들이 접근할 때, 302로 redirect시키는 경우 평가를 안 좋게 한다는 글도 보았다.
그리고 이미 구글봇은 js를 읽을 수 있다고 하니, 따로 해당 부분을 적용할 필요는 없어 보인다.

따라서 각자의 상황에 맞게 해결을 하면 될 것 같다.

이렇게 해결을 한 글은 없는 것 같아
누군가에게는 도움이 되었으면 하면서 글을 남긴다.

11월의 마지막 날이다!

여유를 가지고 천천히 내가면 된다.
너무 빠르게 갈려고 하지말고,
지금도 잘하고 있으니깐

작년 초에 하루 12시간씩 공부 못하고 있는,
그래서 열심히 하고 있지 않다고 스트레스 받고 있는 나에게

친구는 이렇게 이야기 했다.
"야 하루 12시간씩 6개월 미친듯이 하는게 노력이 아니야.
하루 30분이든 1시간이든 내가 할 수 있는 만큼을 2년, 3년, 5년 하는게 노력이야"

그때 당시에는 그 말이 너무나도 공감갔다.

근데 지금 다시 생각해보면,
내가 정말 6개월 동안 미친듯이 공부했던 
cafe.naver.com/suhui/11882722

 

토나올것 같았던 5개월의 시간들....그리고 아쉬움.

안녕하세요 올해 22살 청년 입니다. 내년이면 23살이구요 ^^. 올해 5월 26일날 제대 했습니다. 이렇게 라도 저의 5개월 동안의 수능 스토리를 남겨야 되겠다는 생각이 들...

cafe.naver.com

22살의 나에게 이 시간은 노력이 아니었을까?

아니다 이 시간도 분명 노력이었다. 처절한 노력이었고 피나는 노력이었다.
다만 지금 필요한 노력의 결이 다른 것이다.

이제 우리는 평생 나아가기 위해 노력해야 하는 시기에 있고,
그러기 위해서는 매일 매일 꾸준히 내가 할 수 있는 노력이 필요하다.

1가지는 해봤기에, 이번에는 내가 할 수 있는 노력을 해보자.

11월의 마지막 날.
의미 있게 보내보자.

올 한해 여러가지 프로젝트를 진행했지만,
정말 나의 피, 땀, 눈물이 들어간 프로젝트를 마무리하며
회고글을 적어보고자 한다.

사건의 발단

: 현재 다노에서는 매주 or 2주 단위로 1on1 이라는 것을 진행하고 있다. CTO님 혹은 팀장님과 현재 자신이 겪고 있는
개인적인 이슈 혹은 문제점들을 공유하면서 함께 싱크를 맞추어 나가는 자리이다. 올 6월쯤 1on1을 진행하면서,
현재 다노샵 서버를 하고 있지만 다음에 기회가 되면 프론트엔드 쪽도 한번 해보고 싶다 라는 이야기를 했었고,
CTO님께서는 다음에 다노앱안에 위치하고 있는 매거진이라는 탭을 리뉴얼할 예정이니(언제가 될 진 모르지만)
기회가 되면 다음에 한 번 해보겠냐고 하셨다. 그때 당시에는 아무 생각 없이 "예" 라고 대답을 하였다. 물론 그게 언제가 될 진 모르니깐...
(많은 일들이 이렇게 기억 속으로 묻어져가니 이것도 그렇겠지라고 생각하며..)


사건의 시작

: 9월이 시작되면서 CTO님이 갑자기 주말에 슬랙을 주셨다. 다노 매거진 개편 관련된 디자인이 다 되었는데,
병욱님이 한번 프론트 쪽 개발을 해보겠느냐는 이야기였다. 순간 머리 속이 하애졌다. '갑자기 나에게 왜 이런 이야기를 하실까?' 라는 생각도 잠시 6월의 김병욱이 저질렀던 일이 떠올랐다...아아악... 아무튼 내가 뱉은 말이었고, 먼저 가능할지에 대한 일정을 체크했다.  아무튼 기존에 하던 회사 업무 외에 진행해야 하는 업무였고(외주로 진행), 회사 내 개편 업무다 보니 DUE도 어느정도는 명확하게 걸린 업무였다.

처음 받아본 피그마 디자인



때마침 코로나가 심해져서 주말마다 하던 일도 없어졌고, 하여 이번 기회에 좀 쉬어야지 하던 차였다. 일단 주말 일정은 확보,
그리고 있는 추석 연휴. 한글날 등등 휴일도 넉넉했다. 평일 퇴근 후에 업무를 진행하고 휴일을 모두 넣으면 어떻게든 하면 되지 않을까라고 생각했다. (이 일을 하기 전에 프론트엔드를 해본 것은 html, css, 간단한 javascript로 ajax를 써본 것이 다였다.) 

그렇게 나는 6월의 내가 했던 말에 대한 책임을 지기로 했다. 물론 그 동안 프론트엔드를 공부해야지 생각만 하던 나에게
아주 좋은 자극이 될 수 있을거라고 생각했다. 그렇게 2달 간의 기나긴 프로젝트가 시작되었다.


프로젝트의 시작 (9월 초 ~ 9월 중순)

: 정확히 9월 7일날 백엔드 인턴분이 입사하셔서 매거진의 백엔드 부분을 맡아서 개발해주시기로 하셨고, 나 역시도 9월 7일부로 개발을 시작하게 되었다. React라는 것을 한번도 써본적이 없어서, 먼저 공부부터 해야 하였다.

개발 초기 일정을 설정해달라는 CTO님의 말에 감이 없다는 드립을 치고 있는 모습


그렇게 React 기본 강의를 찾아 수강하기 시작했다.
수업은 인프런에서 공짜 수업으로 시작했다. 인프런에서 react를 검색하면 여러 수업들이 나오는데 나는 John Ahn님의 수업을 들었다. (www.inflearn.com/instructors/217966/courses)

 

인프런 - John Ahn의 강의들을 만나보세요.

인프런은 누구에게나 성장의 기회를 균등하게 부여하기 위해 만들어진 온라인 학습, 지식 공유 중개 플랫폼 입니다. 개발, 프로그래밍, IT, 영상 편집, 그로스 해킹, 블록체인, 마케팅, 디자인, 금

www.inflearn.com

다양한 수업들이 많은데, 내가 들은 것은 유튜브 클론 코딩 그리고 해당 수업을 듣기 전에 들으면 좋다고 참고자 올려놓으신 boile-plate? 수업이었다. boile-plate 수업을 모두 듣고 유튜브 클론 코딩을 절반까지 들었다. 그렇게 일주일이 훅 지나갔다. ㅠㅠ 나에게는 시간이 그렇게 많지 았다. 아 일단 이렇게 하는 거구나 느낌을 잡고, 일단 프로젝트 start를 끊었다. (시작이 절반이다...)

사내 프론트 개발자분에게 구조에 대한 피드백을 받은 뒤에, 컴포넌트들을 생성하기 시작했다. 그렇게 9월 중순 나의 첫 제대로 된
프론트엔드 프로젝트가 시작되었다.

 

처음 start를 끊고 기뻐서 올린 슬랙 (아이콘을 양 옆으로 띄우고 집에 가겠다고 한다)

지금 다시 생각해봐도.. 정말 답이 없는 시간이었다.


프로젝트의 초기(9월 중순 10월 초)

: 어렵게만 느껴졌단 프로젝트는 생각보다 순탄히 진행되었다. 컴포넌트들을 만들어서 쌓는다는 개념은, 굉장히 참신하면서
그동안 html, css만을 써서 만들던 나에게는 매우 직관적으로 다가왔다. (이래서 사람들이 react, react하는 구나라고 잠깐 생각할 수 있었다.) 그리고 이미 잘 만들어져 있는 라이브러리 들이 많았다. (특히 슬라이더 및 롤링 배너, 스크롤에 따라서 특정 부위를 따라다니게 하는 sticky 기능은 짱이었다.)

그리고 무엇보다 중요한, 업무시간을 확보하였다.
현재 다노에서는 출근 시간을 조정할 수 있어서 2가지 패턴으로 시간을 확보해보았다.
먼저 8시까지 출근해서 9시 30분까지 매거진 업무를 진행하고 9시 30분부터 6시 30분까지는 회사 업무, 그리고 식사 이후에 다시 10시까지 매거진 업무를 진행하는 1가지 형태와 그냥 8시부터 오후 5시까지 회사 업무를 진행하고 쭉 이어서 10시까지 매거진 업무를 진행하는 2가지 형태였다. 

결론적으로는 2번째 형태(일찍 회사 업무를 마무리하고 이후에 매거진 업무를 진행하는 형태)가 더 업무가 잘되어서 2번째 형태로 시간 확보를 하였다.

이건 뭔가 나의 고질적인 문제점이기도 한데, 일단 앞에 목표가 있게 되면 그 이외의 부분들은 크게 신경을 쓰지 않게 되는 것 같다.
그렇게 나에게 이 매거진을 끝낼 때까지 다른 일들은 모두 2순위로 밀어두었다. 

며칠 뒤 진행 사항을 공유하며 혼자 감격한 순간



프로젝트의 위기

: 생각보다 초기에 쭉쭉 잘나가던 프로젝트였는데 (나중에 안 사실이지만, 그냥 화면에 보이게 만드는 것보다는 디테일한 부분이 훨씬 시간이 오래 걸리고 어려운 것이었다. 이때까지만 하더라도 화면에 그리면 되겠지라고 생각만 하고 있었다.) 생각지도 못하게, 탈장이라는 병에 걸리게 되었다. 탈장은 말 그대로 장기가 약해진 피부벽을 뚫고 나온 것인데, 수술 이외에는 치료법이 없다고 한다. 

처음에는 그냥 아래배 쪽이 불룩하게 튀어나와서 "뭐지 염증인가" 하고 편하게 생각하고 있었는데, (마침 추석 연휴라서 병원에도 가지 못했다.) 추석 연휴 이후에 병원에 가보니 탈장이라고 하였다. 그 동안 아래배 쪽에 불룩하게 튀어나와 있었던 게 장기였다니!!!! 
진단을 받자마자 급격하게 아파지기 시작하였다.ㅠㅠ(그 동안도 아프긴 하였지만 참을만 하였는데, 진단을 받고나니 갑자기 10배는 더 아파진 느낌이었다.)

그렇게 급하게 수술 날짜를 잡고, 수술을 진행하였다.(아악 안돼 내 휴가.. 흑흑) 생각보다 탈장이라는 병에 걸리는 사람들이 많았고,
그렇게 큰 병도 아니었지만 문제는 일상 생활이 매우 불편해진다는 것이었다. 일단 오랜 시간 앉아 있는게 굉장히 힘들어졌다.
일단 업무외에 시간을 투자해서 해당 프로젝트를 진행해나가야 했기에 나에게 오랜 시간 앉아 있을 수 있는 것은 매우 중요했는데,
그게 어려워지다보니 프로젝트도 시간을 내기 어려웠다.

자연스럽게 컨디션도 급격하게 나빠지기 시작했다. 이미 한 달 정도의 시간을 퇴근 이후의 시간들 그리고 주말, 추석 연휴까지 모두 시간을 쏟고 있어서 정신적으로나 신체적으로나 매우 힘들었지만, 아무튼 내가 하겠다고 하였고 나는 거기에 책임을 지고 싶었다. 


프로젝트의 Detail

:  
전체적인 그림을 그리는 것은 한 달정도 안에 마무리를 했던 것 같은데, 생각보다 디테일한 부분에서 신경 쓸 부분이 많다.
그 동안은 서버가 진행되는 동안 Mocking api를 활용하여 대부분 get요청으로만 화면을 뿌려주었다. (post man에서 간단하게 mocking api를 만들 수 있다.) 그러다가 서버가 붙게 되면서 여러 가지 신경써야 할 부분이 많았다. 사전에 맞추었지만 변수명이 틀린 부분들도 있었고, 우리 생각처럼 잘 작동하지 않았다.

그리고 디테일하게 신경쓸 부분이 필요 했던 게 많았는데, 바로 상단 카테고리바와, 검색창이었다.

문제가 되었던 메인 카테고리바

사실 저렇게 화면에 보이게 하는 것은 어렵지 않았다. 다만 개발 요구사항은 쉽지 않았다.
"일주일 이내의 새로운 글이 있을 때는 빨간 버튼이 보였으면 좋겠어요. 하지만 만약에 고객이 해당 카테고리를 클릭한 적이 있으면 빨간점이 사라져야 해요. 근데 또 만약에 고객이 클릭하고 난 다음에 새로운 글이 또 올라오면 빨간점이 또 보여야 해요"

즉 우리가 생각하던대로 새로운 글(일주일 이내)이 있으면 빨간버튼이 있어야 하고, 그 새로운 글이 우리가 해당 카테고리를 클릭하게 되면 더 이상 새로운 글이 아니다라는 것이다. 너무나도 자연스러운 액션인데, 이걸을 개발하기 위해서는 말로 정리가 되어야하고, 정리가 되어야 코드로 작성할 수 있는데, 쉽지 않았다.

이것을 해결하기 위해서는 해당 사용자가 언제 각 카테고리들을 클릭했는지 저장시켜놔야했다.
일주일 이내의 글이 있을 수 있지만, 그 글이 사용자가 그 카테고리를 클릭했을 당시에 있었던 글인지 아닌지는 또 판단이 필요했다.
이것을 해결하기 위해 서버에서 일주일 이내의 글이 있는지에 대한 정보와, 최신 발행글의 시간을 가지고 왔다.

그리고 프론트에서는 고객이 각 카테고리를 클릭한 정보들을 localstorage에 저장시켜놓고 비교하였다.
기본적으로 일주일 이내의 글이 없다고 하면 아예 빨간 버튼을 보이지 않게 하였고, 만약에 일주일 이내의 글이 있다면,
고객이 해당 카테고리를 마지막에 누른 시간과, 그 카테고리의 최신글의 시간을 비교하였다. 그래서 만약에 해당 카테고리를 누른 시간이 더 늦다면, 해당 고객이 그 카테고리를 눌렀을 당시 이미 그 글은 보였으니 빨간점을 붙이면 안되었고, 그렇지 않다면 빨간점을 붙이게 하여 해결하였다. (항상 서버만 로직을 짜면 된다고 생각했는데... 정말 이번 기회에 많은 반성을 하였다. 프론트엔드도 복잡한 로직이 굉장히 많다.)

그리고 또 하나 카테고리의 요청사항이 있었다.
"각 카테고리를 눌렀을 때 그 카테고리를 보던 위치로 갔으면 해요"
이것도 너무나 당연하게 볼 수 있는데, 이것을 구현하기 위해서는 각 카테고리마다 마지막 보던 위치를 기억하고 있어야 했다.
그래야 그 카테고리를 눌렀을 때 해당 위치로 이동할 수 있었다. 앱에서는 이게 그렇게 어렵지 않게 구현이 가능하다고 하는데, 웹에서는 
각 카테고리를 누를 때 마다 다시 api를 호출하고 랜더링을 다시 해줘야하기 떄문에, 다른 방법이 없었다. (아마 있겠지만 찾아봐도 보이지 않았다.) 그래서 각 카테고리마다 마지막 보던 위치를 저장시켜 놓았다. 그래서 현재 매거진에는 각 카테고리를 누를 때마다 마지막에 보던 위치를 찾아서 이동한다.

 


그리고 정말 쉽지 않았던 검색창 interaction

처음 검색창을 눌렀을 때, 그리고 입력하기 위에 커서를 위에 눌렀을 때, 최근 검색어 저장, 검색 결과 등 등 다양한 컴포넌터들이 상황에 맞게 랜더링이 되어야 했다.

그리고 또 검색하다가 해당 검색어를 지웠을 때, 등등 우리가 그 동안 자연스럽게 사용하던 부분이 막상 구현을 하려고 하니
그렇게 막막할 수 없었다.

처음 검색창을 눌렀을 때는 인기검색어가 나와야하고, 검색창을 클릭하면 최근 검색어가, 그리고 검색을 하면 해당 검색어가 최근 검색어에 저장되어야 하고, 검색어를 삭제했을 때는 다시 인기검색어로 나오는 형태로 구현이 되어야 했다.

3개의 컴포넌트가 상황에 따라서 나와야 하다보니 복잡한 부분이 많았지만, 적절하게 어떻게 분기를 태워서 해결해냈다.


사실 이 밖에도 신경써서 구현한 부분이 많았지만 그것은 모든 개발자들이 겪는 어려움일거라고 생각한다.
그래도 조금 더 자랑해보자면,

처음보자 마자 멘붕을 불러일으켰던 사진 속 +버튼 링크연결 / 카카오톡 공유 / SSR 우회작업 

등이 있다. 조금 더 디테일한 부분들은 추후에 하나씩 다뤄보고자 한다.

아 그리고 정말 쉽지 않았던 데이터심는 작업ㅠㅠ
정말 데이터 심는 작업이 너무 쉽지 않았다. 오히려 요건이 까다로울 때는 개발보다 더 어려운 부분도 있었다.

분명 2시간~ 3시간정도면 끝나는다는 CTO님의 말을 철석같이 믿고 있었는데... 주말 온전히 2틀을 사용했는데도,
끝내지 못했다. 예를 들면 이런 요건도 있었다. 
"슬라이딩 배너에 상품들이 여러가지 있는데 각각의 상품들이 50% 이상 1초 이상 보였을 때 이벤트를 보내주세요"
ㅎㅎ 구현을 떠나 말로도 어려운 이벤트 심는 작업이었다. ㅠㅠ (회사내에 이미 구현되어 있던 것들을 많이 이용하였다...ㅎㅎ)

데이터만 주말 이틀 내리 심고 분노의 슬랙 (하루 일할 수 있는 시간은 18시간이다...) 



프로젝트의 마무리

그래서 이 프로젝트가 과연 끝났을까? 
처음 프로젝트를 시작할 때, 너무나도 막막했던 시간이었다. 그리고 항상 새롭게 오셔서 바로 매거진 서버를 맡게 된 나온님과
이야기 했던 것은 어떻게든 이 비둘기를 날게 하자 였다.

비둘기야 날자

그렇게 2달이 지나 우리 비둘기를 날았다. 그리고 정말 많은 분들의 도움으로 생각보다 멋진 모습으로 날았다.

리뉴얼된 매거진은 여기서 볼 수 있다. (사실 다노앱을 깔면 매거진의 숨겨진 기능들도 사용할 수 있다.)
dano-magazine.dano.me/main

 

습관성형을 위한 모든 것, 다노

좋은 습관이 만드는 건강한 라이프 스타일 정보를 지금 확인해 보세요!

dano-magazine.dano.me


사실 나는 개발만 한 것이고, 이 모든 것들은 정말 많은 분들이 함께 이루어냈다.

새롭게 매거진을 디자인 해주신 디자이너분들과
새롭게 리뉴얼된 매거진에 따라서 다시 컨텐츠를 일일이 만들어주신 컨텐츠 마케터분들,
정말 귀찮은 질문을 계속해서 받아주신 주변의 많은 개발자분들,
데이터를 잘 심고, 트레킹 하기 위해 노력해주신 데이터사이언티스트분들,
앱 안에 들어가는 것이다보니 많은 추가 작업을 해주신 앱 개발자분들,
안정적으로 서비스가 돌아갈 수 있도록 도와주신 인프라 개발자분,
지치지 않고 옆에서 정신 수양을 도와주신 CTO님까지

정말 정말 많은 분들의 도움이 없었다면, 이 모든 것들이 불가능 했으리라 생각한다.
이번 작업을 하면서 내가 개인적으로 가지고 있던, 다른 분야에 대한 진입장벽도 깨진 것 같다.

개발자는 프로젝트를 하면서 성장한다는 말이 있다.
나도 이번 기회를 통해서 한 단계 더 성장했기를 기대해본다.

마지막은 실언으로 마무리!

 

react에서 datetime을 한글 "2020년 11월 10일"과 같은 형태로 변경해야하는 이슈가 있었다.
(디자이너 분이 2020년 11월 10일과 같이 해주셨는데... 바로 걸렸다ㅠㅠ)

여러 가지 방법을 찾아보다가 정말 초간단 변경할 수 있는 방법을 찾아서 공유한다.
바로 moment js 라이브러리를 사용하는 것인데, 
정말 내가 원하는 모든 형태로 구현할 수 있다.

긴말 할 것 없이.. 코드로 간단하게 해보면

export function change_date(published_at){
    var moment = require('moment');

    const publish_date = moment(published_at).format('YYYY년 MM월 DD일')
    return publish_date
}

 

이렇게 하면 published_at으로 받은 datetime을 원하는 format으로 변경할 수 있다.
예시를 보면 대부분 .format('YYYY-MM-DD')와 같은 형태로 있어서 이렇게만 쓸 수 있는줄 알았는데,
내가 원하는 어떤 형태로도 변경할 수 있다.

나와 같이 고생하는 사람이 없기를 바라면서 적어본다!

 

react 웹폰트 초간단 적용하기(react create app 사용시)

정말 초간단 적용 방법입니다. 다른 것 설치하고 할 필요 없습니다.

 

제 로컬에는 폰트가 잘 깔려 있어서 이상이 없었는데..
safari에서는 폰트가 깨지는 문제가 있었습니다.

바로 cdn으로 import해와서 쓰는 방법입니다.

 

보통 구글 폰트에서 바로 link ref를 가지고 와서 사용하는 방법이 일반적입니다.
이건 정말 link 한줄만 넣으면 되기 때문에 간단한 프로젝트를 하기에는 적합합니다.

해당 [Browse Fonts - Google Fonts](https://fonts.google.com/) 페이지에서

원하는 폰트를 선택한 뒤에 
해당 link를 가지고 와서 react public에 있는 index.html 의 head 부분에 넣어주면 끝이 납니다.

 

 

하지만 이렇게 되면 해당 폰트를 계속 import 해오는 시간이 걸리기 때문에
실제로 이루어지는 서비스에서는 사용하는 것을 추천드리고 싶지 않습니다. 

그래서 해당 폰트를 다운 받아서 저장한 뒤 사용할 예정입니다.
그럼 매번 import 해올 필요가 없기 때문에 성능을 매우 높일 수 있습니다.

 

먼저 사용할 폰트를 다운 받습니다.

여기서 주의 할 점이 있습니다.

제가 사용할 noto sans cjk kr 폰트를 기본으로 설명 드리겠습니다.
일단 원본 font 파일을 다운 받는 것은 여기서 진행하였습니다.
[Google Noto Fonts](https://www.google.com/get/noto/)

근데 여기서 다운 받아보니 폰트 용량만 하더라도 100mb가 훌쩍 넘는 것을 볼 수 있었습니다.
(이걸 거면 그냥 import해서 쓴다고 ㅠㅠ)

그래서 찾아보니 해당 폰트의 필요한 폰트들만 추려서 다시 만드는 서브셋 작업을 거치면 된다는 것을 알게 되었습니다.

[한글 웹 폰트 경량화해 사용하기 | Coderifleman's blog](https://blog.coderifleman.com/2015/04/04/using-korean-web-fonts/)

해당 글을 참고하여서 진행하였습니다.


여기 보면 사용할 text들을 넣는 것도 있는데 그것은 

폰트 모음집

[https://raw.githubusercontent.com/nacyot/korean_subset_glyphs/master/glyphs.txt]

여기서 다운 받아서 넣어주었습니다.

 

근데 결론적으로 이야기 드리면... 이렇게 일일이 파일 다운받고 하실 필요가 없습니다.

(일본어로 된 파일이라 무슨 말인지 모르겠는게 함정입니다...)

해당 폰트를 서브셋 작업을 해놓으신 분들이 있습니다. (ㅠㅠ 고마우신 분들)
[본고딕(Noto Sans CJK) 경량화 웹폰트 | NONRIA](https://nonria.com/post/104/)

여기서 해당 파일을 다운 받습니다. 
그럼 경량화된 웹폰트가 준비되었습니다.


이제 저희의 react에 적용해보겠습니다.

하 이것도 정말 여러 방법들이 많았는데, 결국 제가 찾은 제일 간단한 방법으로
적어보도록 하겠습니다.

먼저 src 아래에 
styles / fonts 디렉토리를 만듭니다.

그리고 거기 안에 경량화된 웹폰트를 다 복사해서 넣습니다.

 

그리고 이제 src root경로에 있는 index.css 파일을 열고선언을 해줍니다.

@font-face {
  font-family: 'Noto Sans CJK KR';
  font-style: normal;
  font-weight: 100;
  src: url("styles/fonts/NotoSansKR-Light.woff2") format('woff2'),
  url("styles/fonts/NotoSansKR-Light.woff") format('woff'),
  url("styles/fonts/NotoSansKR-Light.otf") format('truetype')
}

@font-face {
  font-family: 'Noto Sans CJK KR';
  font-style: normal;
  font-weight: normal;
  src: url("styles/fonts/NotoSansKR-Regular.woff2") format('woff2'),
  url("styles/fonts/NotoSansKR-Regular.woff") format('woff'),
  url("styles/fonts/NotoSansKR-Regular.otf") format('truetype')
}


@font-face {
  font-family: 'Noto Sans CJK KR';
  font-style: normal;
  font-weight: 500;
  src: url("styles/fonts/NotoSansKR-Medium.woff2") format('woff2'),
  url("styles/fonts/NotoSansKR-Medium.woff") format('woff'),
  url("styles/fonts/NotoSansKR-Medium.otf") format('truetype')
}

@font-face {
  font-family: 'Noto Sans CJK KR';
  font-style: normal;
  font-weight: bold;
  src: url("styles/fonts/NotoSansKR-Bold.woff2") format('woff2'),
  url("styles/fonts/NotoSansKR-Bold.woff") format('woff'),
  url("styles/fonts/NotoSansKR-Bold.otf") format('truetype')
}

 

각각의 말이 무엇이냐면 
font-family에  "Noto Sans CJK KR"
font-style에 "normal"
font-weight에 "100"이
들어가 있으면 해당 src에 있는 부분들을 적용해주겠다고 선언해준 것입니다.

 

그리고 src에 3개가 들어가 있는데 그 이유는

/* IE6-IE8 */

url('../fonts/test.eot?#iefix') format('embedded-opentype')/* Super Modern Browsers */

url('../fonts/test.woff2') format('woff2')

/* Modern Browsers */

url('../fonts/test.woff') format('woff')

/* Safari, Android, iOS */       

url('../fonts/test.ttf') format('truetype'),

 /* Legacy iOS */

url('../fonts/test.svg#OpenSans') format('svg');

 

여러 상황에 맞게 대응하기 위해서 입니다.

저렇게 하고 새로 고침하면!!

 

잘 적용된 것을 볼 수 있습니다.!

끝!

'프론트엔드' 카테고리의 다른 글

SPA에서 서버사이드랜더링 하지 않고 SEO 우회하기  (4) 2020.12.05
react datetime 한글(년월일)로 변경하기  (1) 2020.11.10
리액트 dom  (0) 2020.09.20
리액트 구조잡기  (0) 2020.09.06
리액트 시작하기  (0) 2020.09.06

최근에 개발자로 취업하신 분들이 연락이 오신다!!
정말 너무 기쁜 일이다.

힘든 아침을 맞아주는 정말 기분이 좋은 메시지!!


사실 이럴 때 정말 보람을 느낀다.

옛날에 처음 법인 회사를 만들 때의 회사명이 
FABL(주식회사 파블) 이었다.

For A Better Life의 줄인 말이었다. 사람들의 삶을 좀 더 좋게 개선해주고 싶다는 
비전을 가진 회사였다.

나는 누군가에게 좀 더 나은 삶을 제공해주는 행동을 하면서, 
삶을 보람을 찾았던 것 같다. 그리고 그게 좀 더 큰 규모에서 할 수 있는 창업을 지속적으로 시도했다.

그런 목표를 가지고 하다보니 좀 더 크게 임팩트를 미칠 수 있는 소프트웨어 쪽 사업을 하고 싶다고 생각했다.
그렇게 개발자를 해야 되겠다 생각했고, 개발자로 도전을 하게 되었다.

그리고 내가 지금 어떤 도움을 줄 수 있을까 많은 고민을 했다.
그렇게 시작하게 된 게 "개발자 취업 입문 개론" 수업이다.
내가 비전공자로 개발자를 준비하며 겪었던 시행착오를 다른 분들은 겪지 않았으면 하는 마음으로
수업을 시작했다.

그렇다보니 탈잉과 인프런 수업을 하면서 수익을 목표로 하기 보다는,
새롭게 개발자를 준비하시는 분들이 나와 같은 시행착오를 겪지 않았으면 하였고,
그런 마음으로 수업을 진행하였다.

그렇다보니 탈잉 3시간 수업은 항상 늦어지게 마련이었고,
인프런에 올라온 문의도 하나 하나 정말 열심히 답변해드리고
오픈 채팅방에 오는 문의도 퇴근 후 따로 연락을 드리거나 전화상담들을 도와드리며
해결해 나갔다.

그리고 그 결실들이 점점 맺어지고 있다.

지난 주에만 해도 취업하신 분이 3분이나 연락주셨다!!
(승*님, 혜*님, 진*님,  너무 축하드려요)

정말 정말 내 일 같이 너무 기쁜 일이었다!!

그 분들이 또 새로운 도전을 해나가시는게 정말 대단하는 
생각이 든다. (사실 나도 반성을 많이 하게 된다.)

그리고 그 안에서 내 수업이 조금이라도 도움이 되고 임팩트를 미쳤다면,
그것으로 내 역할을 다 한 것 같다.

자 이제 밥을 얻어 먹어보자... ㅎㅎㅎ!!!!!

해당 수업은 아래와 같다.

www.inflearn.com/course/개발자-취업-입문-개론?inst=b3611dbc

 

비전공자를 위한 개발자 취업 개론 - 인프런

개발자 취업 입문 개론 수업입니다. 평생 한 직업만 하실 게 아니라면, 꼭 한번은 개발자를 도전해 보시길 추천드려요! 비전공자 혹은 현재 다른 업무를 하더라도, 상관없습니다. "쌀 팔다 개발

www.inflearn.com

[드디어...!!!!!!!!!!!!! 추가 소식 전달!]

안녕하세요 쌀 팔다 개발자하고 있는
김병욱입니다! 

저 역시도 29살의 나이에,
처음으로 개발이라는 것을 배우면서
무엇을 해야 할지 몰라 많은 시행착오를 겪었습니다.

그리고 현재는 잘 성장하여,
3년차 백엔드 개발자로 일하고 있습니다.
새롭게 개발 시작하시는 분들이 저와 같은 시행착오를

겪지 않았으면 좋겠다는 생각으로 개발자가 된 이후로
지속적으로 강의를 해왔었는데, 항상 시간이 부족해서
아쉬움이 가득이었습니다.

그래서, 정말 큰 맘 먹고 올해 1월부터 책을 적기 시작했습니다.
회사 출근 전 퇴근 후 최대한 시간을 내서(피,땀, 눈물 ㅠㅠ), 제가 알고 있는,
그리고 부족한 것은 주변 개발자분들에게 물어가며
정말 열심히 적었습니다!

그리고 10개월이 지난, 이제서야 이 책이 정말 곧 빛을 보려고 합니다.
개발 시작하시는 분들이 정말 꼭 읽고 시작했으면 좋겠다는 생각에
용기내어 이렇게 글을 적습니다. 최소 2개월은 save하실 수 있으실거에요!
(책 팔아서 돈을 번다는 것은 정말... 너무 어려운 일이고, 그러고 싶지도 않습니다.)

정말 이 책이 정말 개발 시작하려는 분들에게는
조금이라도 도움이 되었으면 좋겠습니다.
그것이면, 전 정말 만족할 것 같습니다.

현재 텀블벅에서 펀딩 진행 중입니다.
주변에 개발자 하시고 싶어하시는 분들이 있다면 많이 추천해주세요!
https://tumblbug.com/tomorrow_programmer?ref=discover

 

취업까지 로켓배송! 개발자 취업 가이드 [오늘부터 개발자]

개발자 취업까지 수백시간 줄여줄 비전공자 취업 입문 개론 [오늘부터 개발자]

www.tumblbug.com

감사합니다!

 

 

가을이 가까워 와서 그런지 집이 유난히 따듯한 느낌이 들지 않았어요.
날씨도 추워지고...!!

그래서 
디자인이 굉장히 특이한 캔들 워머를 구매했습니다.
상자부터 굉장이 특이해요

 

상자를 보시면 아시겠지만, 색상은 블랙. 화이티, 핑크로 나누어져 있어요!!

그중에서 저는 블랙 색상을 구매했습니다.

 

쿠팡에서 구매했는데, 디자인이 너무 깔끔해서 보자마자 바로 구매했어요!


그럼 실물 공개!!! 벌써 특이하죠?? ㅎㅎ
기존보던 워머와는 굉장히 달라요~

 

제대로 꺼내놓고 보면 전구도 2개나 따로 들어가 있어요.

전구 끼우는게 어려울까봐 걱정되시나요??!!! 전혀 걱정할 게 없어요

 

요렇게 아랫 부분에 그냥 돌려서 끼우기만 하면 됩니다. 5초면 누구나 할 수 있어요!!

두둥 5초만에 끼우고 기대를 하면서 ..!!!

완성된 모습이에요!!

책상위에 올려놓고 켜보았어요.

 

무엇보다 좋은 것은 밝기를 조절하는 부분이, 돌려서 조절하는 형태로 되어 있어서

본인이 원하는 밝기로 언제든지 조절해서 사용할 수 있어요!!

 

또 전구색이다 보니 집에 분위기를 띄어주는데도 한 몫을 하구요.

양키캔들 블랙체리도 구매했는데,

 

양키캔들도 오면 다시 한번 찍어서 올려볼게요.무게감도 있어서 매우 만족하고, 기존 디자인과 다르다는 것도

매우 칭찬합니다.

 

가격은 25,000원 정도 했어요!

 

쿠팡에서카페 캔들워머라고 검색하시면 바로 나옵니다!

 

coupa.ng/bDrPMY

 

COUPANG

쿠팡은 로켓배송

www.coupang.com

이 포스팅은 쿠팡 파트너스 활동의 일환으로, 이에 따른 일정액의 수수료를 제공받을 수 있습니다.

'자취생활' 카테고리의 다른 글

m1에서 pycharm 버벅일 때  (4) 2021.08.31

개발자가 되면 좋을까에 대한 질문들이 많다.

사실 나의 수업을 듣는 가장 많은 사람들이 하는 질문이기도 하다.
"개발자가 되면 실제 생활은 어떤가요? 만족도는 어떠신가요?"

개발자에 대한 좋은 이야기들로 개발을 시작하려고 하는데,
막상 또 검색을 해보면 좋지 못한 이야기들이 많고,
혹시라도 개발자가 된 이후에 개발자가 잘 맞지 않으면 어쩔까에 대한
걱정이 많은 것도 같다.
(그리고 그런 환상들을 깨주는 글들도 너무 많다.)

사실 이것에 대한 이야기도, 본인이 어떤 곳에서 처음 개발을 시작하고 있는지 
혹은 현재 어디서 일을 하는지에 따라서 굉장히 큰 영향을 미칠 것 같다.

일단 나에 대해서 이야기 해보면,
나는 자체 서비스를 하는 회사에서 일을 하고 있고,
그렇다 보니 일반 고객들과 바로 마주하는 서비스의 서버를 개발한다.

이것의 장점은 내가 개발한 것을 
사람들이 바로바로 이용할 수 있다는 장점이 있고,
관리자 페이지 쪽을 개발할 때는 운영단에서의 이슈를 해결해주어서
실제 관리자들분들이 만족해하시는 모습들을 보며 보람을 찾는다.

반대로 단점도 있다.
24시간 언제든지 에러에 대응해야 하고,
실제 고객들이 활용하는 서비스에 배포를 진행한다는 것은
매번 배포를 진행할 때마다 손에 땀을 쥐게 하는... 일들의 연속이다.ㅠㅠ

하지만 그럼에도 불구하고,
개인적인 생각으로는 개발자에 대한 업계의 대우,
주어진 업무들을 스스로 개발해나가면서 느끼는 일의 만족도 등은 다른 직군에 대해 
높은 편이라고 할 수 있을 것  같다. (과거 페이퍼 작업을 할 때는, 나의 쓸모에 대해서 
매우 많이 고민도 했었다.)

어떤 분들은 그렇게 이야기한다.

"비전공자가 개발자 시작했다가 1년도 못 채우고 돌아간 것을 수도 없이 봤다."
"개발자가 잘 맞지 않으면 금방 다시 돌아갈 거니깐 적성 먼저 파악해"

사실 나는 이런 이야기들에 대해서 조금은 반대적인 생각을 가지고 있다.

내가 회사에 1년 넘게 있으면서도 비전공자로 개발자로 시작하신 분들을 많이 보았고,
그중에서 개발자를 포기하신 분은 한 분도 없었다.

그리고 적성이 잘 맞는지에 대한 유무는...
생각보다 개발자로 생활을 해봐도 파악하는 게 쉽지 않다.
반대로 우리가 다른 직업을 하고 있다면, 그 직업이 정말 적성에 잘 맞아서
하고 있는 사람들은 과연 얼마나 될까 생각해본다.

그런 의미에서, 
결국 본인이 현재 있는 곳에 따라서 보고 느끼고 생각하게 된다.
그 말은 개개인마다 생각이 모두 다를 수 있다는 것이다.
그러므로 개발자가 되기도 전에 다른 사람들의 이야기를 너무 많이 참고하는 것은
큰 도움이 되지 못하는 것 같다.


개발자가 되서 행복한 게 아니라,
본인이 생각한 직업을 해볼 수 있다는 것에 의의를 두더라도,
100세 인생에서 한 번쯤은
개발자라는 직업을 한번 꼭 도전해봐도 괜찮다고 생각한다.

그리고 무엇보다,
내가 생각한 것들을 바로 만들어 볼 수 있다는 것은,
개발자로서의 최고의 장점이 아닐까 한다!


개발자로 도전하고자 마음먹었으면,
최대한 빨리 개발자가 되어서 생활해보기를 추천한다.

www.inflearn.com/course/개발자-취업-입문-개론?inst=b3611dbc

 

비전공자를 위한 개발자 취업 개론 - 인프런

개발자 취업 입문 개론 수업입니다. 평생 한 직업만 하실 게 아니라면, 꼭 한번은 개발자를 도전해 보시길 추천드려요! 비전공자 혹은 현재 다른 업무를 하더라도, 상관없습니다. "쌀 팔다 개발

www.inflearn.com

 

[드디어...!!!!!!!!!!!!! 추가 소식 전달!]

안녕하세요 쌀 팔다 개발자하고 있는
김병욱입니다! 

저 역시도 29살의 나이에,
처음으로 개발이라는 것을 배우면서
무엇을 해야 할지 몰라 많은 시행착오를 겪었습니다.

그리고 현재는 잘 성장하여,
3년차 백엔드 개발자로 일하고 있습니다.
새롭게 개발 시작하시는 분들이 저와 같은 시행착오를

겪지 않았으면 좋겠다는 생각으로 개발자가 된 이후로
지속적으로 강의를 해왔었는데, 항상 시간이 부족해서
아쉬움이 가득이었습니다.

그래서, 정말 큰 맘 먹고 올해 1월부터 책을 적기 시작했습니다.
회사 출근 전 퇴근 후 최대한 시간을 내서(피,땀, 눈물 ㅠㅠ), 제가 알고 있는,
그리고 부족한 것은 주변 개발자분들에게 물어가며
정말 열심히 적었습니다!

그리고 10개월이 지난, 이제서야 이 책이 정말 곧 빛을 보려고 합니다.
개발 시작하시는 분들이 정말 꼭 읽고 시작했으면 좋겠다는 생각에
용기내어 이렇게 글을 적습니다. 최소 2개월은 save하실 수 있으실거에요!
(책 팔아서 돈을 번다는 것은 정말... 너무 어려운 일이고, 그러고 싶지도 않습니다.)

정말 이 책이 정말 개발 시작하려는 분들에게는
조금이라도 도움이 되었으면 좋겠습니다.
그것이면, 전 정말 만족할 것 같습니다.

현재 텀블벅에서 펀딩 진행 중입니다.
주변에 개발자 하시고 싶어하시는 분들이 있다면 많이 추천해주세요!
https://tumblbug.com/tomorrow_programmer?ref=discover

 

취업까지 로켓배송! 개발자 취업 가이드 [오늘부터 개발자]

개발자 취업까지 수백시간 줄여줄 비전공자 취업 입문 개론 [오늘부터 개발자]

www.tumblbug.com

감사합니다!

 

# urls.py에 해당 api를 들어올 수 있도록 url을 만들어 준다.
re_path(r'^inner/static/$', static_serving),


# view에 작성할 파일 

import mimetypes

# static 경로 설정(static파일 경로에 있는 파일을 다운로드)
STATIC_ROOT = getattr(settings, 'STATIC_ROOT')


@api_view(['GET'])
def static_serving(request):

    file_name = request.GET.get('filename', '')

    if file_name == '':
        return None


    fl_path = STATIC_ROOT+'/{}'.format(file_name)
    filename = file_name

    fl = open(fl_path, 'r')
    mime_type, _ = mimetypes.guess_type(fl_path)
    response = HttpResponse(fl, content_type=mime_type)
    response['Content-Disposition'] = "attachment; filename=%s" % filename


    return response

장고로 static 파일을 다운받을 수 있는 경로를 만들어줄 수 있다.

해당 경로로 filename을 담아서 요청을 하게 되면 파일을 다운 받을 수 있다.
다운로드 요청 경로

https://127.0.0.1:8000/inner/static/?filename='hello.py'


 

 

버튼이 중간으로 가지 않았던 이유....

 

하 ㅠㅠ 너무 답답했다.

button을 만들고, margin : auto를 주었는데도,

이놈의 버튼은... 움직이지 않았다 ㅠㅠㅠㅠㅠㅠㅠ

 

왜 이렇게 안 움직이는 것일까..

 

너무 답답했다. 

 

근데... 정말 허무하게 회사의 프론트 개발자분의 한 줄로 끝나버렸다.

 

display: block; 

 

... 뭐야?? 어리둥절 하고 있는 나에게

친절하게 html의 태그들의 type은 3가지라고 이야기 해주었다.

 

inline와 block 그리고 inline-block 

 

기본적으로 block은 우리가 보는 화면은 한 줄을 차지하고 표시하고자 하는 것을 나타내고

inline은 한 줄을 다 차지하고 나타내지 않고, 다른 것들과 속해서 나타나게 된다.

 

block의 예시로는 P태그를 바로 생각해보면 될 것 같고, h태그 들도 모두 한 줄씩을 차지하고 있다.

그에 비해 image태그 혹은 button 태그는 inline태그라, 아무리 내가 margin auto를 주어도 

해당 줄을 다 차지하고 있지 않아서, 중앙정렬이 되지 못한 것이다.

 

이럴 때 해결할 수 있는 방법은 inline이 기본인 button을 

block으로 바꾸어주는 것 => display: block으로 해주는 것이다.

 

오늘도, 또 한 수 배워 간다 ㅠㅠ

참고 :

[[CSS] display - block과 inline 그리고 inline-block](https://seungwoohong.tistory.com/23)

'HTML' 카테고리의 다른 글

HTML 06. Server만들기(POST 및 CGI)  (0) 2020.01.16
HTML 05. Server만들기(get)  (0) 2020.01.16
HTML 04. clone page+Bootstrap  (0) 2020.01.16
HTML 03. form, input, label  (0) 2020.01.16
HTML 02. table 만들기  (0) 2020.01.16

기본적 정의 : 

GraphQL은 페이스북에서 만든 데이터 질의어이며, 'gql'이라고 한다. gql은 서버에 작성된 쿼리를 통해 데이터를 조회하는 방식이 아니라, 클라이언트에서 쿼리를 작성하여 필요한 데이터만 조회하는 방식을 제공한다. 또한, 하나의 EndPoint를 가지기 때문에 개발 규모에 따라 EndPoint의 복잡도가 증가하는 REST API보다 개발이 간편하다. 여러 데이터 집합에서 데이터를 조회하는 경우 gql은 하나의 쿼리로 조회가 가능하지만, REST API는 Request를 여러번 시도해야 한다. REST API도 한번의 Request로 처리가 가능하지만, 매번 여러개의 데이터 집합을 조회하기 때문에 자원의 낭비를 초래한다.

 GraphQL은 데이터의 구조를 정의하는 스키마(Schema)와 데이터 조회를 위한 쿼리(Query), 데이터 위한 뮤테이션(Mutation), 조회 결과에 대한 구현을 위한 리졸버(Resolver)로 구성되며, 이 외에 API명세서의 기능을 하는 인스로펙션(Instropection)으로 구성된다.

 

혼자서 공부하며 내린 정의 :

기존 rest api에서 발생하는 문제는  크게 2가지 였습니다.

overfetch와 underfetch

그 중 overfetch는

user의 정보를 요청하는 api를 보냈을 때, 내가 필요한 정보보다 훨씬 많은 정보들이 넘어오는 것이었습니다.

보통 프론트에서는 현재 user의 name만 필요로 하겠지만, 보통 rest api에서 고객 정보를 요청하면 해당 고객의 모든 정보를  보내주도록 구현되어 있어서, 더 많은 리소스 낭비로 이어졌습니다.

그리고 underfetch의 경우, 

만약 고객의 장바구니 정보, 혹시 좋아요한 물품 정보를 모두 함께 보고 싶다고 했을 경우,

user/cart/ 뿐만 아니라 user/wish/ 등 여러가지 api를 요청해야 하는 이슈가 있습니다. 무엇보다 중요한 것은 이게 점점 서비스의 규모가 커져감에 따라서 관리해야 하는 endpoint들이 기하급수적으로 늘어날 수 있다는 것입니다. 이는 개발자나 클라이언트에게 부담이 될 수 있습니다.

 

GRAPHQL은 위에서 설명한 것처럼 REST API의 한계를 극복하기 위해 나왔습니다.

endpoint는 통상 1개만 생성하고, 클라이언트에서 필요한 데이터는 클라이언트에서 직접 쿼리를 작성하여 호출 반환하도록 합니다.

 

위의 overfetch문제를 graphql에서는 간단하게 해결 가능합니다.

query {

    user(id:1){

        name

    }

}



{

    "data" : {

        "user":{

            "name" : 'byeonguk'

        }

    }

위의 underfetch 문제도 graphql에서는 간단하게 해결 가능합니다.

query {

    user(id:1){

        name

        cart {

            product_name,

            product_price

        }

        wish {

            product_name,

            product_price

        }

    }

와 같이 해결 할 수 있습니다.

 

물론 장단점이 있습니다.

 

장점으로는

  • 클라이언트가 필요한 데이터만 반환할 수 있고

  • 1번의 호출로 원하는 데이터를 한번에 가져올 수 있습니다. (REST API의 N+1 problem을 해결할 수 있습니다.)

  • 확장이 용이합니다.

 

단점은

  • 러닝커브

  • 캐싱 기능 구현이 어려움( 대부분의 언어에서 라이브러리로 직접 구현)

 

'서버' 카테고리의 다른 글

mysql replication 설정  (0) 2021.09.08
Error: Unknown command: cask 에러를 만났을 때  (3) 2021.03.13
nslookup 이란  (0) 2020.08.31
초보자를 위한 REST API  (0) 2020.06.21
Docker란(도커란)  (0) 2020.06.02

돔이란 :

웹브라우저와 관련된 객체들의 집합을 브라우저 객체 모델(BOM: Brower Object Model)이라고 부른다. 이 브라우저 객체 모델을 이용하여 Brower와 관련된 기능들을 구성한다. DOM은 BOM 중의 하나이다. DOM은 document object model의 약자이다. 문서 객체 모델인데, 문서 객체란 <html> < body>와 같은 html문서의 태그들을 javascript가 이용할 수 있는 개체로 만드는 것. 그것을 문서 객체라고 한다.

또 뒤에 model이 붙어 있는데 여기서는 문서 객체를 인식하는 방식정도로 해석하면 좋을 것 같다.

즉 웹브라우저가 html 페이지를 인식하는 방식이다. 


보통은 데이터가 변화하게 되면 양방향 바인딩으로 처리


변화(Mutation)
=> 특정 변화가 있으면 모델에 변화를 일으키고, view에 로직을 만들어준다.
그리고 화면에 다시 띄어준다.

 

페이스북에서는 다른 생각

만약에 변화가 일어나야 하면 mutation하지말고
기존에 있던 view를 날려버리고 새로 만들어버리면 어떨까?
=> 브라우저는 돔기반으로 작동하기 떄문에, 성능적으로 엄청난 문제가 있을 수 있다.

그래서 virtual dom이 나왔다.

가상의 돔이다. 

변화가 일어나면 브라우저의 돔에 새로운 것을 넣는 것이 아니라 javascript로 이루어진 가상의 돔에 랜더링을 하고 기존의 돔과 비교를 하고 정말 비교가 필요한 부분만 업데이트 한다 

 

 

 

어떤 변화가 일어나면 가상의 돔에 그린 다음에 실제 돔에 변화를 준다.

따라서 성능적으로 굉장히 우수하다.

 

리액트 다운로드 => npx create-react-app .
를 진행하면 아래와 같이 자동적으로 여러가지 폴더들을 생성해준다.

 

 

terminal을 열어서 npm run start를 하면 처음 리액트 화면을 만나 볼 수 있다. (감동 ㅠㅠ)

 

리액트의 시작은 package.json에 있는 

"scripts": {

"start": "react-scripts start",

이 부분이 시작된다.

react-script는 src 에 있는 index.js이고 index.js를 보면

ReactDOM.render(

<React.StrictMode>

<App />



</React.StrictMode>,

document.getElementById('root')

);

이런 부분이 있다. 이 말은 root id라는 부분에다가 

app이라는 부분을 채워넣어주겠다는 것인데, 여기서 app은 src/app.js이고

root id는 public/index.html에 가면 id="root"라고 설정해놓은 부분이 있다.

여기 div안에 app.js 파일이 들어간다고 생각하면 된다.

주의 => react의 webpack은 src 폴더 안에 있는 애들만 정리해서 주므로, public 폴더 안에 파일을 넣지 않도록 주의하자.

리엑트는 라이브러리다.
페이스북에서 만들어졌고, 2013년도 발표가 되었다.

컴포넌트로 이루어져 있어서, 모듈처럼 재사용성이 굉장히 뛰어나다.

virtual DOM => real Dom vs virtual Dom

real DOM은 list가 10개가 있는 것 중 1개가 변화가 일어나면, real Dom에서는 모든 것을 없애고 다시 가져온다.

virtual DOM에서는 하나만 가지고 올 수 있다.

어떻게 업데이트 된 것만 가지고 올 수 있냐면 => 스냅샷을 찍어놓고, 스냅샷을 찍어 둔 것과 차이를 분석해서, 바뀐 부분만 real DOM에서 바꾸어 준다.

Babel : 최신 자바스크립트 문법을 지원하지 않는 브라우저들을 위해서 
최신 자바스크립트 문법을 구형 브라우저에서도 돌 수 있게 변환시켜줌

webpack : 웹사이트를 만들 때 단순하게, 자바스크립트 몇개 파일 html이런게 아니라 라이브러리, 프레임워크를 사용하면서 굉장히 복잡하게 되었다. 이렇게 복잡하게 된 것을 webpack을 활용해서 간단하게 묶어 준다. => src폴더만 모아준다.

원래 리액트 앱을 처음 실행하기 위해선 webpack이나 babel 같은 것을 설정하기 위해
엄청 나게 많은 시간이 걸렸으나 지금은 create-react-app Command로 바로 시작할 수 있다.

react 다운 받을 때 => npx create-react-app .

npm vs npx의 차이는?
npm => 라이브러리들이 저장되어 있는 곳? npm run build package.json에 모두 저장되어 있다. (node package manger)

-g => global로 다운로드(usr/local/bin) / 따로 하지 않으면 local에 다운로드 된다.(node module)

옛날에 react를 다운 받을 때는 global에 다운받아서 사용했으나,
이제는 npx를 이용해서 그냥 npm registry에 있는 것을 사용할 수 있다.
disk space를 낭비하지 않고 항상 최신 버전을 사용할 수 있다.

 

nslookup은 

Name server lookup의 약자로서

 

DNS 서버로 부터 여러 가지 정보를 얻을 수 있는 명령어 이다.

호스트 이름으로 부터 IP주소를 얻어낼 수 있다.

 

도메인 네임서버는 IANA(IANA(Internet Assigned Numbers Authority)는 인터넷 할당 번호 관리기관의 약자로 IP 주소최상위 도메인 등을 관리하는 단체이다. 현재 ICANN이 관리하고 있다. 처음에는 서던캘리포니아 대학교 정보 과학 학회의 존 퍼스텔이 서던캘리포니아 대학교 정보 과학 학회와 미국 국방부 간에 맺어진 계약 아래 관리했으며, 퍼스텔은 미국 상무부 계약으로 ICANN이 설립 될 때까지 이 업무를 수행했다.)

라는 곳에서 실제 도메인 주소를 가지고 오나 

이러한 요청을 계속 주게 되면 네트워크상에 부하가 가중되기 때문에,

한 번 가져온 주소는 DNS server에 저장하고

호스트의 요청시 그 안에 정보를 가지고 온 후 반환해준다.

 

test

 

 

궁금증 : 

그럼 해당 Address로도 접근이 가능해야 하는데 왜 접근이 불가능할까?

=> 원래는 접근 가능해야 하나, 요즘은 보안상의 이슈로 직접 IP접속을 차단한 경우가 많아,

열리지 않는 경우가 많다.

 

참고 : [네트워크 - nslookup 이란 무엇인가 : 네이버 블로그](https://m.blog.naver.com/PostView.nhn?blogId=on21life&logNo=221364857511&proxyReferer=https:%2F%2Fwww.google.com%2F)

'서버' 카테고리의 다른 글

Error: Unknown command: cask 에러를 만났을 때  (3) 2021.03.13
Graphql이란  (0) 2020.09.26
초보자를 위한 REST API  (0) 2020.06.21
Docker란(도커란)  (0) 2020.06.02
NAS란(나스란)  (0) 2020.06.01

+ Recent posts