상근이는 요즘 설탕공장에서 설탕을 배달하고 있다. 상근이는 지금 사탕가게에 설탕을 정확하게 N킬로그램을 배달해야 한다. 설탕공장에서 만드는 설탕은 봉지에 담겨져 있다. 봉지는 3킬로그램 봉지와 5킬로그램 봉지가 있다.
상근이는 귀찮기 때문에, 최대한 적은 봉지를 들고 가려고 한다. 예를 들어, 18킬로그램 설탕을 배달해야 할 때, 3킬로그램 봉지 6개를 가져가도 되지만, 5킬로그램 3개와 3킬로그램 1개를 배달하면, 더 적은 개수의 봉지를 배달할 수 있다.
상근이가 설탕을 정확하게 N킬로그램 배달해야 할 때, 봉지 몇 개를 가져가면 되는지 그 수를 구하는 프로그램을 작성하시오.
(입력 : 첫째 줄에 N이 주어진다. (3 ≤ N ≤ 5000))
나의 풀이
N = int(input())
five = N // 5 + 1
three = N // 3 + 1
result = 0
end_point = False
for i in range(five + 1):
if end_point == True:
break
for j in range(three):
if N == (((five-i) * 5) + (j * 3)):
result = (five - i) + j
end_point = True
break
if result == 0:
result = -1
print(result)
five와 three는 각각 5킬로그램 봉지와 3킬로그램 봉지의 최대 개수 + 1 이다
5킬로그램 봉지 개수가 five 이하이고, 3킬로그램 봉지 개수가 three 이하일 때,
정확히 N킬로그램을 표현하는 경우 중, 5킬로그램 봉지 개수가 가장 큰 경우를 찾는 알고리즘을 작성했다.
그리디 문제로 인식했으나, 풀이는 그리디 알고리즘을 사용했다고 보기가 좀 그렇다.
찾아보니 아직 안 배운 동적 프로그래밍(DP)에 가까운 것 같다.
남의 풀이
def sugar_bag(N):
bag_3 = 0
bag_5 = N // 5
r = N % 5
while (bag_5 >= 0):
if r % 3 == 0:
bag_3 = r // 3
return bag_3 + bag_5
bag_5 -= 1
r += 5
return -1
N = int(input())
print(sugar_bag(N))
import math
# 최소공배수(LCM)을 구하는 함수
def lcm(a, b):
return a * b // math.gcd(a, b)
a = 21
b = 14
print(math.gcd(21, 14)) # 7 (최대공약수)
print(lcm(21, 14) # 42 (최소공배수)
gcd(a, b)는 a와 b의 최대공약수를 구하는 메서드이다.
최소공배수는 = (두 수의 곱) / (최대공약수) 공식에 따라 위와 같이 구할 수 있다.
(공식을 간단히 증명하자면,
A와 B의 최대공약수를 GCD라 하고, A = a x GCD, B = b x GCD 라 하자.
array = [i for i in range(10)]
print(array) # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
간단한 반복문으로 위와 같은 배열을 생성할 수 있다.
반복문과 조건문 사용
array = [i for i in range(10) if i % 2 == 1]
print(array) # [1, 3, 5, 7, 9]
조건문을 추가할 수 있다.
삽입 인자 변경
array = [i * i for i in range(10)]
print(array) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
리스트에 삽입할 인자를 변경할 수 있다.
2차원 배열 생성
# 모든 성분이 0인 3 x 4 크기의 2차원 배열
array = [[0] * 3 for _ in range(4)]
# [0] * 3 => [0, 0, 0]
print(array)
# [[0,0,0], [0,0,0], [0,0,0], [0,0,0]]
# 잘못된 사용
array = [[0] * 3] * 4
2차원 배열을 생성할 때 매우 유용하게 사용할 수 있다.
('_'는 0, 1, ..., n의 값을 가질테지만, 사용하지 않는 값이라는 뜻으로 '_'로 표시한다.)
잘못된 사용은 [0, 0, 0]라는 배열 하나를 생성하고, 같은 위치를 참조하는 4개의 배열을 생성한다.
즉, 동일한 배열([0, 0, 0]) 하나를 세 번 참조하는 것이므로 의도와 다르다.
일반적 코드와의 비교
## 리스트 컴프리헨션
# 0 ~ 19까지의 홀수
array = [i for i in range(20) if i % 2 == 1]
print(array)
## 일반적인 코드
# 0 ~ 19까지의 홀수
array = []
for i in range(20) :
if i % 2 == 1 :
array.append(i)
print(array)
인프런에서 제공하는 Nest.js 무료 강의. 다른 인프런 무료강의들처럼 유튜브로 배포된 영상을 강의형태로 모았다.
쉽고 재밌습니다.
강의 후기
🔎학습 내용
- Nest.js 기본 요소 설명(MVC 패턴에 대한 간략한 설명도) - 간단한 CRUD 구현 (DB 연결 X) - Pipe 이용(유효성 체크 등을 위한 미들웨어) - DB 연동 후 CRUD 수정(Postgresql & TypeORM) - JWT를 활용한 인증 로직 구현 - 게시물 접근 권한 로직 구현 - 그 외 (Log, Configuration)
🔎학습 시간
- 강의시간 : 약 10시간 - 공부시간 : 약 20시간
🔎수강 조건
- 웹 프레임워크(Express면 더 좋고)에 대한 기본적인 이해
이해가 없어도 들을 수 있는 난이도이기는 하지만, 기초적인 것을 다 설명해주시지는 않기 때문에 기본적인 이해는 필요할 것 같다.
🔎수강 대상
- Nest.js 기초를 빠르게 잡고 싶은 사람 - Express 개발자 (Nest 함 써보세요 편합니다 ^^)
주관적 평가
👍좋았던 점
1) 적당한 난이도 어렵지는 않지만 직접 프로젝트를 만들 수 있을 정도의 예제로 구성되어 있어 좋았다! 강의 수강 후 바로 개발 시작하면 될듯.
2) 깔끔한 구성
유튜브에 배포된 강의가 맞나 싶을 정도로 강의 구성이 깔끔했다.
3) 왜케 재밌지?
너무 재밌어가지고 밥 먹을 때도 자꾸 다음 강의 생각나고 그래서 하루 만에 다 들었다.
👎나빴던 점
버전 문제가 좀 있는데요, 강사님 깃에서 package.json, package.lock.json 그대로 복사해오면 해결되더라구요..
프로젝트 기술 스택을 Express에서 Nest.js로 옮기기 위해 급하게 들었던 강의. 아티클이랑 깃허브 리파지토리 뒤져서 그냥 시작할까하다가, 강의 한 번 들어보고 싶어서 들었는데 너무 잘한 선택이었다!
서버 파트원으로서 세미나, 스터디, 그리고 대망의 앱잼까지 다양한 경험을 통해 많은 것을 느끼고 배울 수 있었다.
개발 경력 2달짜리 JB였던 나에게 과분할 만큼 많은 지식과 경험이 쏟아지는 시간이었다.
자부할 만큼 많은 것을 배운 경험도, 더 열정을 쏟지 못해 아쉬웠던 경험도 떠오른다.
그중에서도 기술적으로 성장한 부분과 아쉬웠던 부분을 기록해보고자 한다.
동아리 활동에서 얻은 엄청난(?) 감상들은 네이버 블로그에 정리해보았다.
서버 파트 세미나
1주차 세미나 때 충격을 아직도 잊지 못한다. 파트장님의 세미나 강의는 내가 들었던 어떤 강의보다 명료했다.
하지만, 아무런 CS 지식이 없는 나는 쓰레드가 어쩌고 큐가 어쩌고 하는 내용들을 거진 알아들을 수 없었다.
더군다나 매주 4시간의 세미나 내용은 시중 프로그래밍 강의 만큼이나 내용이 꽉차서 복습하는 데 거진 두세배의 시간이 걸렸다.
아무튼 나는, 이해가 안 되는 내용은 될 때까지 복습하고 정리하면서 최대한 모든 내용을 따라가려고 노력했다.
Javascript, Typescript
Python만 조금 다뤄본 나는 새로 배운 Javascript가 너무 어색했다. 사실 처음에는 문법이 간결한 Python이 그리워 JS에 정 자체가 붙지 않았다. 그런데 TS까지 이해하려니 코드를 칠 때마다 혀에서 피맛이 나는듯 거부감이 들었다.
그래도 어렵게 들어온 동아리, 최선을 다해보자며 세미나 복습, 유튜브 강의, 각종 아티클로 어찌저찌 따라갔다. 지금은 TS 사용이 전혀 어색하지 않고, Python 만큼이나 생각하는 것을 코드로 표현할 수 있게 된 것 같다.
특히 기억에 남는 내용은 Promise에 관한 것.
사실 아무리 복습하고, 아티클을 수십 개(구라 아님) 읽어봐도 도무지 이해가 되지 않던 내용이 Promise와 Async, Await이었다.
너무 열 받아서 이틀을 내리 Promise에 꼴았다. 이해가 될 때까지 강의와 아티클을 찾아봤고, 결국 나름의 방식대로 이해해서 정리했다.
Node.js, Express, MongoDB
세미나에서 다룬 기술 스택 3개.
처음 접할 때는 모든 게 어색했다. 간신히 익혔던 Django의 MTV 패턴과도 비슷한 듯 달랐고, 디렉토리 구조도 너무 달랐다. 어느 파일이 어디서 어떤 역할을 하는지 하나도 감이 오지 않았다.
하지만 파트장님의 선물인 보일러 플레이트를 반복해서 사용하면서 처음 다뤄보는 MVC 패턴과 컨트롤러 서비스 로직 분리, 각종 모듈과 타입 명시 파일의 분리된 구조를 완전히 이해할 수 있었다. 요청이 들어와 미들웨어와 라우터를 거쳐 서버 내부의 각 단에 전달되고, 가공되고, Response되기 까지의 과정을 나름대로 잘 이해할 수 있었다. 심지어는 구조가 너무 달라 혼동되던 Django의 구조도 더 명확하게 이해할 수 있었다. 이래서 '프레임워크는 도구일 뿐'이라고 말하는 듯싶었다.
MongoDB는 사실 세미나 때 사용하고 앱잼 때 사용해보지 못해서 조금 아쉽지만, 그래도 나름대로 열심히 이해하고 사용해보았다.
꼴랑 2달 공부한 JB였지만, SQLD도 따고 프로젝트 DB도 직접 설계해본 헛짬바로 관계형 DB가 너무 익숙했다. 비관계형 데이터베이스에서 어떻게 연관관계를 표현할 것이며, 어떻게 효율적인 스키마 구조를 설계할 수 있을지 도무지 감이 오지 않았다. 아직도 의문이 완전히 풀리지는 않았지만, 관계형과는 다른 특성을 조금은 이해하고 참조가 아닌 직접 조회를 효율적으로 수행하기 위한 스키마를 설계해야 함이 조금은 와닿게 느껴진다.
스터디
The SOPT(솝트 30기)에서 내가 활동한 스터디는 금잔디조, AWS 스터디(이하 파트 스터디), 코테 스터디, 회고 스터디(이하 전체 스터디) 총 4개였다.
금잔디조
금잔디조는 서버 파트 YB, OB가 섞여서 필수로 지정되는 세미나 코드 리뷰 그룹이다. 사실 스터디라고 보기엔 애매하지만, 금잔디로부터 너무 많은 것을 배웠기에 적고 넘어가고 싶다.
우선 세미나에 열정을 다했기에 나올 수 있었던 많은 질문들이 오갔다는 것이 좋았다. 그리고 최선을 다해 답변해주던 친구들에게 너무 고맙다. 처음에는 사람이 이렇게 착할 수가 있나 싶어 의구심도 들었지만, 개발 생태계에서 지식 공유에 기여하는 것이 본인의 발전과 명성에도 보탬이 되는 일이라는 것을 알고 나니 이해가 되었고, 더욱 멋져 보였다.
AWS 스터디
가장 아쉬움이 많이 남는 스터디.. 하지만 사람을 얻었다(?)
Udemy에서 구매한 AWS 자격증 강의를 함께 듣는 스터디였다. 인프라 공부는 역시 너무 생소했고 어려웠다. 목표만큼 강의를 많이 듣지는 못했지만, 부분부분 공부한 내용들이 앱잼 때 서버 인프라를 구축하며 도움을 주어 신기했다. Route53 사용법, ELB의 역할, 말로만 듣던 CI/CD의 정의와 구현 방법에 대해 배울 수 있었다. Key와 IAM 계정을 통해 보안을 지키는 방법 또한 익힐 수 있었다.
코테 스터디
사실 다른 것에 바빠 우선순위가 밀렸..지만(강의를 듣는 형식의 스터디였다) 인상적인 순간이 남아 기록하고 싶다.
솝트 내외로 꽤 유명하신 분께서 스터디를 준비하고 강의해주셨는데, 내용이 알찬 것은 물론이고 그 모습이 너무 멋있었다. 솝트 활동을 하면서 나도 많은 사람을 대상으로 무언가 지식을 전하는 경험을 반드시 해야겠다고 마음을 먹게 되었다.
회고 스터디
는 감상적인 내용이 가득해 이곳에 적지 않겠지만.. 나에겐 솝트 활동의 척추뼈(?)와 같은 존재였다.
앱잼
3주 간의 장기 해커톤 앱잼. 딜리버블이라는 서비스를 만들게 되었고, 명실상부 쌉고수 Sigrid와 함께 서버파트를 맡게 된다.
Sigrid의 리드 하에 Express, MySQL, TypeORM을 사용한 프로젝트를 만들었다. 또한 AWS를 활용한 다양한 인프라적 경험도 했다.
TypeORM과 Repository 구조
세미나에서 다루지 않았던 새로운 스택을 사용하기로 했다. 사실 세미나에서 다뤘던 스택을 제대로 사용해보고 싶은 마음이 있었지만, 새로운 것을 배우는 것도 좋은 경험이 될 것 같다고 생각해 받아들였다. 다만 웹 프레임워크도 바꾸자는 제안은 완곡하게 거절했다. 배운 것을 써먹어는 보고 싶었기 때문.
TypeORM을 사용하면서 Repository를 따로 분리했다. 기존에는 Service 단에서 비즈니스 로직과 더불어 DB에 접근하는 로직까지 포함했다면, 이번 프로젝트에서는 DB에 접근하는 로직을 Repository로 분리했다. 책임을 분리하는 방법과 이점에 대해서 처음 고민하고 배울 수 있는 시간이었다.
디미터 법칙과 객체 지향
객체 지향이란 그저 어디서 주워들은 단어에 불과했다. 제대로 된 공부도 해보지 못한 채로 객체 지향적인 코드를 고민했다. Sigrid는 나에게 디미터 법칙을 소개하고 그것을 고민한 코드를 짜보라는 미션을 선물한다. 부랴부랴 아티클을 읽고 고민하며 코드를 작성한다. 그렇게 객체 지향적인 코드를 짜게 되었냐고 스스로 반문한다면 아니라고 대답할 것이다. 하지만 아무 고민 없이 구현만 되는 코드를 짜던 나에게 어떤 제동이 걸렸고, 그것을 공부하기 위한 허들이 매우 낮아졌다는 것만으로도 큰 의미가 있는 경험이었다.
AWS 인프라
Sigrid가 나에게 처음 제시한 미션은 VPC와 서브넷을 구축하는 것이었다. 디폴트로 생성되는 그것 말고, 새롭게 생성한 서브넷에 우리가 사용할 EC2 인스턴스와 RDS 인스턴스를 집어넣고 안전하게 관리하는 인프라를 구축하라는 것이었다.
그것도 아주 간단한 한 마디 말로 전달한 미션이었다. "VPC 한 번 구축해볼래요?" 말은 쉽지. 드릅게 어려웠다.
그렇게 개발자의 마인드를 배울 수 있었다. 하면 되는 것이다. 어렵고 쉽고는 존재하지 않았다. 해서 되는 것과 되지 않는 것만 존재할 뿐.
(The SOPT 서버파트 블로그에 아티클도 게재했다.)
SSL 인증서를 연결하고 Load Balancer를 이용해 HTTPS로 연결하는 경험도 했다! 클라이언트 단에서 API 연결을 위해 HTTPS 주소가 필요하다고 했다. 임시 방편으로 할 수 있는 방법들이 있었지만, 그보다는 실제 인증서를 구매해 적용해보기로 한다.
Route 53, Elastic Load Balancer 등의 기술을 사용했는데, 아티클을 아무리 보면서 따라해도 과정이 이해되지는 않았다. 하지만 다양한 시행착오를 겪고 그것을 해결하면서, 각 과정이 어떤 의미를 가지고 있는지 대략적으로 이해되기 시작했다. 가령 ELB에서 HTTP 요청(80번 포트)이 HTTPS(443번 포트)로 리다이렉트되면서 SSL 인증을 받는다던가 하는..
막연하기만 했던 인프라 구축에 대한 자신감을 얻을 수 있었다.
Git 협업 방식
Git 공부를 미루고 미루다 앱잼까지 Git 감자 상태였던 나는, Sigrid와의 협업을 통해 깃 브랜치 전략과 Issue, PR을 통한 협업 방식을 체득할 수 있었다. Git을 반드시 기초부터 공부하고 GUI 툴까지 사용해서 Git 마스터가 되리라.
다양한 코드 구현 방식
그 외에도 다양한 방식의 코드를 접하며 익힐 수 있었다. map, filter와 같은 Array 메서드를 적재적소에 사용해보기도 했고, DB에서 쿼리로 조회해온 데이터를 객체 내부의 메서드로 다시 정렬하거나, 생성자를 사용하는 여러가지 용례에 대해서도 배울 수 있었다.
그 밖에도 많은 사람에게 많은 배움을 얻어가는 한 학기였다.
솝트에는 잘하는 사람들과, 열정 넘치는 사람들이 혼재했다.
그들과 함께 호흡하며 공부할 수 있어 정말 영광이었고, 이제야 조금은 이 생태계에 일원으로서의 감정을 느껴 기분이 좋다.
멋지게, 그리고 아주 격하게 성장해서 나의 배움을 많은 사람들에게 공유하고 싶다는 꿈을 꾸는 지금이다.
그런 꿈을 이룬 미래의 어느 한 지점에서, SOPT 30기 활동은 나의 발전의 기폭제였다며 자랑스럽게 말할 것이다.
터미널을 물리적으로 다중화하여, 백그라운드에서 터미널을 실행할 수 있는 프로그램이라고 한다.
screen을 사용해서, 터미널을 꺼도 runserver가 구동되게 하자!
우선 screen을 설치한다.
sudo apt-get install screen
그리고 screen을 생성한다.
screen -S test // test는 screen 이름
생성된 스크린을 조회해보자.
# 현재 생성된 screen list 조회
screen -ls
There is a screen on:
7783.test (07/02/2022 02:10:13 AM) (Attached)
7783이라는 네 자리 숫자가 스크린의 id이다.
Attached는 해당 스크린에 현재 접속해있는 상태라는 표시이다.
ctrl + a + d 를 누르면 해당 스크린에서 빠져나올 수 있다.
그 후 아래와 같이 다시 조회해보자.
# 현재 생성된 screen list 조회
screen -ls
There is a screen on:
7783.test (07/02/2022 02:10:13 AM) (Dettached)
Attached가 Dettached로 바뀐 것을 볼 수 있다.
해당 스크린을 빠져나온 것이다.
이번에는 스크린에 들어가서, runserver를 구동하고 도망나올 것이다.
# 7783 id를 가진 screen으로 다시 attach
screen -r 7783
# 7783.test screen 으로 들어온 상황
python3 manage.py runserver 0.0.0.0:8000
System check identified no issues (0 silenced).
September 30, 2018 - 21:50:28
Django version 2.1.1, using settings 'ypc.settings'
Starting development server at http://127.0.0.1:8000/
Quit the server with CONTROL-C.