728x90

1. 서버란 무엇인가?

  • 일반인의 관점: 인터넷, 맨날 터지는 짜증나는 곳
  • IT관련직 관점: 서비스가 동작하게 만드는 원천, 데이터가 다뤄지는곳
  • FE 개발자 관점
    • 정해진대로(API) 요청(request)을 보내면, 정대진 대로 응답(response)이 돌아오는 곳
    • 모델링, 데이터베이스는 잘모르겠고 내가 클라이언트 개발하게 받고싶은 데이터 내놓고, 내가 넣으려는 데이터 알맞게 넣어줘!
    • 요구하지만 매번 핑계되며 늦게 주는 곳
  • BE 개발자 관점
    • 효율적으로 클라이언트의 요구에 따라 데이터를 건네주고 저장하는 곳
    • 데이터를 처리하는 곳
    • 부하 분산, 인증, 쿼리 최적화, 보안(CSRF)등 조심해서 다뤄야 하는 예민한 아이
    • 한번의 결정이 추후 확장할때 많은 리소스를 소비할수 있으니 신중히 결정!
    • 알면알수록 점점 발전할수 있는 양파같은 매력적인 아이
    • etc...

사전적 정의 같은건 이미 많이 나와있지만 각자의 관점에 따라서는 위와같다!

 

2. 서버는 어떻게 만드는가?

  • python, java, js, php등 많은 프로그래밍 언어를 통해 직접 서버를 만들수 있지만 각각의 언어엔 python-django, java-spring, js-express, php-lalavel과 같이 유명한 서버 프레임워크가 있다. 이 프레임워크를 활용하여 서버를 만들수 있다.
  • full-featured framework (drf) vs not full-featured framework (express)
    • full-featured framework는 이미 서버 개발에 필요한 대부분의 기능이 구현 되어있어서 crud 구현이 간단하며 그저 이용만 하면되지만 이에 맞게 해당 프레임워크에 대한 공부또한 많이 해야한다.
    • not full-featured framework는 서버 개발에 필요한 최소한의 기능만 주어져있어서 아무래도 crud 구현에 비교적 시간을 할애해야 하겠지만 필요한대로 입맛에 맞게 개발할수 있는 장점이 있다.
    • 즉, drf 잘하려면 공식문서 자세히 들여다 봐야한다!!!

3.ORM 이란?

  • Object Relation Mapping
  • SQL(Structured Query Language) 데이터베이스 언어를 python의 환경에 맞게 객체로 쉽게 가져올수 있도록 하는것
  • Table -> Class, Column -> Property, Row -> Instance
#SQL
SELECT * FROM user WHERE ~~

#ORM
User.objects.filter(~~)
  • SQL문에서도 마찬가지지만 drf의 ORM에서는 쿼리를 가져올때 최적화하는 작업이 중요하다!
  • 캐싱, transaction활용, selected_related, prefetch_related등을 활용하여 최적화 작업을 진행한다

4. RESTAPI란?

 

프로젝트(1)프론트, 백엔드 통신 방법(feat.django, react)

새롭게 프로젝트를 시작하며 개발전 1주일간 3파트로 프로젝트 사전 준비를 하였다. (1) 프론트, 백엔드 통신방법 (2) 기술스택 선정, 협업 노하우 (3) token, django user, 소셜로그인 위의 3가지를 사전

leeceo97.tistory.com

위글에 정리를 해뒀다

  • 한마디로, METHOD로 행동을 구분하고, URL에 가져올 자원과 이를 식별할 기준을 나타내며 행동에 대한 응답은 상태코드와 메시지로 응답하는 방식이다.
request  GET(method) https://corin2.com/category(가져올 자원)/:id(식별자)
response  200(행동에 대한 상태코드)  OK(메시지) {"Data": "Oh My God"} (데이터)

5. drf에서의 서버 동작은?

  • request -> middleware -> router -> parser -> viewset(view) -> permission -> serializer -> model -> DB -> model -> serializer -> viewset(view) -> renderer -> response의 과정을 거친다
  • request: 말그대로 클라이언트가 서버로 요청을 보내는과정
  • middleware: 요청에 대한 전/후처리를 하고 싶은것이 있다면 미리 만들어 둔다(ex.인증)
  • router: urls.py 요청을 view로 연결해줌
  • parser: request의 content-type에따라 request data/ request FILES등을 처리(ex. iAmBabo-> i_am_babo)
  • viewset(view): 정확하게 말하면 viewset=view의 집합이며 요청에 따른 알맞은 로직을 수행하는 곳
  • permission: has_permission은 view요청이 들어오기전, has_object_permission은 view요청후 인증 확인
  • serializer: model 직렬화/역직렬화
  • renderer: parser와 반대되는 개념
  • response: request와 반대로 서버가 클라이언트의 요청에 따른 응답을 보내는 과정
728x90
728x90

프로젝트를 완성한후 좀더 발전시킬방법에 대해 학습중이다. 기능 관련해서는 물론 좀더 발전시킬부분이 있지만 내가 경험해보지 않은 부분은 어딜까? 생각하다 요즘은 선택이 아닌 거의 필수로 여겨지고 있는 TDD에 대해 알아보고 적용해보게 되었다.

 

TDD란?

테스트 주도개발(Test Driven Development)은 일종의 개발 방식 또는 개발 패턴을 말한다. 무언가를 개발할 때 바로 개발부터 하는 것이 아니라 개발하려는 항목에 대한 점검 사항을 테스트코드로 만들고 그 테스트를 통과시키는 방식으로 개발을 진행하는 방법이다.

 

-TDD 이전의 테스트 방법

API서버를 만들때 항상 그때그때마다 POSTMAN으로 API에 JSON형식으로 데이터를 전송하고 OK되면 바로 서버에 적용 하는 방법으로 테스트를 진행했다. 사실, 개인적 혹은 소규모의 팀프로젝트를 진행하는 나의 입장에서는 TDD가 그렇게 와닿지도 필요하지도 않았다. 그래서 테스트코드 작성이라는 귀찮은 개념을 다시학습하고 적용할 필요가 없었다.

 

하지만, 프로젝트 규모가 좀더 커지고 API가 다양해진다면? 말이 달라진다. 매번 POSTMAN으로 일일이 확인을 해야하고 복잡하게 얽혀있는 비즈니스 로직에 대해 하나하나 고려해가며 테스트 하기는 물론 쉽지 않고 누락하기 쉽다. 때문에 테스트코드를 작성함으로써 이런실수를 미연에 방지하고 추후 나아가 이걸기반으로 배포 자동화 즉, CI/CD를 적용할때의 기준점을 잡고 진행할수 있다. 물론, 다수의 개발자가 협업하는 회사에서의 TDD는 결국 필수라고 생각한다.

 

DRF에서의 TDD

사실 방법은 다양하다. 이미 파이썬 자체에서 제공하는 라이브러리도 있으며, 그밖의 다양한 방식또한 있겠지만 django라는 완벽한 프레임워크에는 자체적으로 test할수 있는 방법이있다. 매번 python manage.py startapp ~~를 통해 생성되는 test.py가 바로 그방법중 하나이다.

python manage.py test

Found 0 test(s).
System check identified no issues (0 silenced).

----------------------------------------------------------------------
Ran 0 tests in 0.000s

OK

test.py를 전혀 건드리지 않고 위의 명령어를 입력한다면 당연히 아무런 에러가 뜨지 않는다.

하지만, 기존에 작성된 api에 잘못된 형식으로 데이터를 전송한다면? PTSD오는 수많은 에러창이 나온다.

 

대부분의 협업은 drf를 통해 api를 생성한후 클라이언트가 api를 이용하기 때문에 postman에서 테스트 하는것과 같은 방법으로 테스트 코드를 작성한다.

from django.test import TestCase
from rest_framework.test import APIRequestFactory

factory = APIRequestFactory()
request = factory.post('/api/board/', {
                    "title":"asdasdasd",
                    "category":"question",
                    "content":"asdasdasdasd",
                    "user":1,
                    "stack":["python", "java"],
                    "worker":["기획자","디자이너"]
                })

위와 같은 방식으로 테스트 코드를 작성한후 python manage.py test를 통해 테스트 통과유무를 확인하고 에러가 없는걸 확인 했을때 배포하는 식으로 진행하는 방법이다.

 

api 서버를 개발하는 우리 입장에서는 각각의 api에 적합한 데이터를 넣었을때 데이터가 제대로 저장되는지 확인을 하면 되는 부분이므로 아래의 공식문서의 내용을 통해 인증을 포함한 여러 테스트 코드를 작성하면 된다.

 

Testing - Django REST framework

 

www.django-rest-framework.org

TDD라는 말만 들어봤지 실제로 어떻게 작성해야하고 무엇을 테스트 해야하는걸까?라는걸 모르고 있었던 나에겐 사실 꼭필요했던 정보라 짧게나마 기록을 해두게 되었다ㅎㅎ..

728x90
728x90

링크드리스트(LinkedList)

1.구조

  • Hash Table: 키(key)에 데이터(value)를 저장하는 데이터 구조
    • key를 통해 바로 데이터를 받아올 수 있으므로, 속도가 획기적으로 빨라짐
    • 파이썬 딕셔너리 타입이 해시테이블의 예(key를 가지고 바로 데이터(value)를 꺼내옴)
    • 보통 배열로 미리 hash table 사이즈만큼 생성 후에 사용(공간과 탐색 시간을 맞바꾸는 기법 -> 해쉬테이블의 공간을 늘림으로써 충돌로 인한 추가적인 자료구조 알고리즘을 만들지 않기 때문)
    • 단, 파이썬에서는 해쉬를 별도 구현할 이유가 없음 - 딕셔너리 타입을 사용하면 되기 때문

2.알아둘 용어

  • 해쉬(hash): 임의 값을 고정 길이로 변환하는것
  • 해쉬 테이블: 키 값의 연산에 의해 직접 접근이 가능한 데이터 구조
  • 해싱함수: key에 대해 산술 연산을 이용해 데이터 위치를 찾을수 있는 구조
  • 해쉬값 또는 해쉬 주소: key를 해싱함수로 연산해서, 해쉬 값을 알아내고, 이를 기반으로 해쉬 테이블에서 해당 key에 대한 데이터 위치를 일관성있게 찾을 수 있음
  • 슬롯: 각각의 데이터를 저장할 수 있는 공간
  • 저장할 데이터에 대해 key(입력값)를 추출할 수 있는 별도 함수도 존재할 수 있음
  • 배열보다 해쉬테이블이 좋은 이유: 검색할 때 배열같은경우는 입력값에 대해 처음부터 확인을 해야하지만 해쉬테이블은 입력값을 통해서 바로 검색을 하여 가져올 수 있기 때문에 더 많이 쓰이게 된다.

3.장단점과 주요 용도

  • 장점
    • 데이터 저장/읽기 속도가 빠르다.(ex. 검색 속도)
    • 해쉬는 키에 대한 데이터가 있는지(중복) 확인이 쉽다.
  • 단점
    • 일반적으로 저장공간이 좀더 많이 필요하다.
    • 여러 키에 해당하는 주소가 동일할 경우 충돌을 해결하기 위한 별도의 자료구조가 필요하다
  • 주요용도
    • 검색이 많이 필요한 경우
    • 저장, 삭제, 읽기가 빈번한 경우
    • 캐시구현시(중복확인이 쉽기 때문)

4.파이썬에서의 해시 테이블의 활용 예 - 딕셔너리(Dictionary)

5.직접 해쉬테이블 구현해보기

hash_table = list([0 for i in range(8)])

def get_key(data): # 전달 받은 데이터를 암호화
    return hash(data)

def hash_function(key): # 특정 고윳값으로 키값 반환
    return key % 8

def save_data(data, value): # hash_function으로 받은 키값으로 데이터 저장
    hash_address = hash_function(get_key(data))
    hash_table[hash_address] = value
    
def read_data(data): # 전달받은 데이터를 기반으로 반환받은 키값을 통해 데이터 출력
    hash_address = hash_function(get_key(data))
    return hash_table[hash_address]

여기서 한가지 의문점이 든다. 그렇다면 전달받은 데이터를 기반으로 키값을 만들어내는데 이때 같은 키값이 나오게 된다면 이를 어떻게 처리하고 저장이 될까? 이때 해쉬테이블의 가장 큰 문제점이 나온다. 바로 충돌(collison)이다. 그래서 해쉬테이블은 따로 충돌알고리즘을 구현해야하는데 대표적으로 2가지 방식이 있다.

-Chaining 기법

  • 개방 해슁 또는 Open Hashing 기법 중 하나: 해쉬 테이블 저장공간 외의 공간을 활용하는 기법
  • 충돌이 일어나면, 링크드 리스트라는 자료 구조를 사용해서, 링크드 리스트로 데이터를 추가로 뒤에 연결시켜서 저장하는 기법
hash_table = list([0 for i in range(8)])

def get_key(data):
    return hash(data)

def hash_function(key):
    return key % 8

def save_data(data, value):
    index_key = get_key(data)
    hash_address = hash_function(index_key)
    if hash_table[hash_address] != 0: # 저장할 공간에 이미 데이터가 존재할때
        for index in range(len(hash_table[hash_address])):
            if hash_table[hash_address][index][0] == index_key:
                hash_table[hash_address][index][1] = value
                return
        hash_table[hash_address].append([index_key, value])
    else:
        hash_table[hash_address] = [[index_key, value]]
    
def read_data(data):
    index_key = get_key(data)
    hash_address = hash_function(index_key)

    if hash_table[hash_address] != 0:
        for index in range(len(hash_table[hash_address])):
            if hash_table[hash_address][index][0] == index_key:
                return hash_table[hash_address][index][1]
        return None
    else:
        return None

-Linear Probing 기법

  • 폐쇄 해슁 또는 Close Hashing 기법 중 하나: 해쉬 테이블 저장공간 안에서 충돌 문제를 해결하는 기법
  • 충돌이 일어나면, 해당 hash address의 다음 address부터 맨 처음 나오는 빈공간에 저장하는 기법
    • 저장공간 활용도를 높이기 위한 기법
hash_table = list([0 for i in range(8)])

def get_key(data):
    return hash(data)

def hash_function(key):
    return key % 8

def save_data(data, value):
    index_key = get_key(data)
    hash_address = hash_function(index_key)
    if hash_table[hash_address] != 0:
        for index in range(hash_address, len(hash_table)):
            if hash_table[index] == 0:
                hash_table[index] = [index_key, value]
                return
            elif hash_table[index][0] == index_key:
                hash_table[index][1] = value
                return
    else:
        hash_table[hash_address] = [index_key, value]

def read_data(data):
    index_key = get_key(data)
    hash_address = hash_function(index_key)
    
    if hash_table[hash_address] != 0:
        for index in range(hash_address, len(hash_table)):
            if hash_table[index] == 0:
                return None
            elif hash_table[index][0] == index_key:
                return hash_table[index][1]
    else:
        return None

+) 위와 같은 해결기법을 통해 해결가능하지만 근본적으로 빈번한 충돌을 방지하기 위해서는 해쉬테이블의 저장공간을 애초에 많이 생성해주면 된다!

728x90
728x90

사실 이번 코딩테스트 준비 파트를 기초부터 들어가게 된 원인이 된 녀석이다... 면접때 코딩테스트 당시 풀었던 코드에대해 시간복잡도를 여쭤보셨는데 이부분에대한 정의가 안되어있어서 대답조차 못했기때문...ㅎ... 그리어렵진 않다.

알고리즘 복잡도 표현방법

1.알고리즘 복잡도 계산이 필요한 이유

하나의 문제를 푸는 알고리즘은 다양함

  • 정수의 절대값 구하기(1,-1)
    • 방법1:정수값을 제곱한 값에 다시 루트 씌우기
    • 방법2:정수가 음수 인지 확인해서, 음수일 때만 -1을 곱하기
    • 즉, 다양한 알고리즘 중 어느 알고리즘이 더좋은지를 분석하기 위해, 복잡도를 정의하고 계산함

2.알고리즘 복잡도 계산항목

  • 시간 복잡도: 알고리즘 실행속도
  • 공간 복잡도: 알고리즘이 사용하는 메모리 사이즈
  • 가장 중요한 시간 복잡도를 이해하고 계산할 수 있어야함 -> 공간복잡도는 아무래도 비중이적음

알고리즘 시간 복잡도의 주요 요소는 반복문이다. -> 입력의 크기가 커지면 커질수록 알고리즘 수행시간이 증가함

알고리즘 성능 표기법

  • Big O (빅-오) 표기법: O(N)
    • 알고리즘 최악의 실행 시간
    • 가장 많이/일반적으로 사용
    • 아무리 최악의 상황이라도, 이정도의 성능을 보장한다는 의미
  • Ω (오메가) 표기법: Ω(N)
    • 오메가 표기법은 알고리즘 최상의 실행 시간
  • Θ (세타) 표기법: Θ(N)
    • 세타 표기법은 알고리즘 평균 실행시간을 표기
  • 시간 복잡도 계산은 반복문이 핵심 요소이며, 계산 표기는 최상, 평균, 최악 중, 최악의 시간인 Big-O표기법을 중심으로 익히면 됨

3.Big-O 표기법

  • 빅 오 표기법, Big-O 표기법 이라고도 부름
  • O(입력값)   
  • 입력 n에 따라 결정되는 시간 복잡도 함수
  • O(1), O( 𝑙𝑜𝑔𝑛 ), O(n), O(n 𝑙𝑜𝑔𝑛 ), O( 𝑛2 ), O( 2𝑛 ), O(n!)등으로 표기함
  • 입력 n 의 크기에 따라 기하급수적으로 시간 복잡도가 늘어날 수 있음
  • O(1) < O( 𝑙𝑜𝑔𝑛 ) < O(n) < O(n 𝑙𝑜𝑔𝑛 ) < O( 𝑛2 ) < O( 2𝑛 ) < O(n!)
  • 참고: log n 의 베이스는 2 -  𝑙𝑜𝑔2𝑛 
  • 단순하게 입력 n에 따라, 몇번 실행이 되는지를 계산
  • 표현식에 가장 큰 영향을 미치는 n 의 단위로 표기 -> 상수회 무시
  • 예시

-무조건 2회(상수회)실행: O(1)

if n>10:
	print(n)

-n에따라, n번, n+10번 또는 10n+10번등 실행: O(n)

variable = 1
for num in range(3):
	for index in range(n):
		print(index)
# 따져보면 2n+2회이지만 결국 시간복잡도는 2n

-n에 따라, 𝑛2번 , 𝑛2+1000번,  𝑛2+1번실행한다: O(𝑛2)

variable = 1
for i in range(300):
	for num in range(n):
		for index in range(n):
			print(index)
  • 성능 판단 예시: 1부터 n까지의 합을 구하는 알고리즘
# 입력값 n을 정렬하여 모두 합
def sum_all(n):
    total = 0
    for num in range(1, n + 1):
        total += num
    return total
#시간복잡도: n

# 덧셈 알고리즘 이용
def sum_all(n):
    return int(n * (n + 1) / 2)
#시간복잡도: 1

같은 문제이더라도 어떤 알고리즘을 이용하냐에 따라 시간 복잡도가 다르게 나옴 즉, 시간복잡도가 1인 2번째 알고리즘의 성능이 더욱 좋다.

728x90
728x90

링크드리스트(LinkedList)

1.구조

  • 연결리스트라고도 함
  • 배열은 순차적으로 연결된 공간에 데이터를 나열하는 데이터 구조
  • 링크드 리스트는 떨어진 곳에 존재하는 데이터를 화살표로 연결해서 관리하는 데이터 구조
  • 링크드 리스트 기본 구조와 용어
    • 노드(Node): 데이터 저장 단위(데이터, 포인터)로 구성
    • 포인터(Pointer): 각 노드 안에서, 다음이나 이전의 노드와의 연결 정보를 가지고 있는 공간
  • 배열은 미리 특정한 공간을 예약해두고 그공간을 쓰는구조이지만, 이에반해 링크드 리스트는 미리 예약을 해두지 않고 필요할때마다 그공간을 추가할수 있는 구조이다.
  • 보통 파이썬에서 링크드 리스트를 구현시, 파이썬 클래스를 활용 -> 파이썬 객체지향 문법의 이해가 필요함

2.장단점

  • 장점
    • 미리 데이터 공간을 할당하지 않아도됨 -> 배열은 미리 데이터 공간을 할당 해야함
  • 단점
    • 연결을 위한 별도 데이터 공간이 필요하므로, 저장공간 효율이 높지 않음
    • 연결정보를 찾는 시간이 필요하므로 접근 속도가 느림
    • 중간 데이터 삭제시, 앞뒤 데이터 연결을 재구성해야 하는 부가적인 작업이 필요

3.직접 링크드 리스트 구현해보기

class Node:
    def __init__(self, data, next=None):
        self.data = data
        self.next = next
    
class NodeMgmt:
    def __init__(self, data):
        self.head = Node(data)
        
    def add(self, data):
        if self.head == '':
            self.head = Node(data)
        else:
            node = self.head
            while node.next:
                node = node.next
            node.next = Node(data)
        
    def desc(self):
        node = self.head
        while node:
            print (node.data)
            node = node.next
    
    def delete(self, data):
        if self.head == '': 
            print ("해당 값을 가진 노드가 없습니다.")
            return
        
        if self.head.data == data: # 삭제하는 데이터가 헤드일경우
            temp = self.head
            self.head = self.head.next
            del temp
        else: # 삭제하는 데이터가 중간,맨뒤일 경우
            node = self.head
            while node.next:
                if node.next.data == data:
                    temp = node.next
                    node.next = node.next.next
                    del temp
                    return
                else:
                    node = node.next
  • head의 경우, 리스트의 첫시작을 알기위해 임의로 지정한 것
  • 링크드리스트를 다시금 학습하며 개념을 파악할수 있었다. 그리고 생각보다 구현하는데 애를먹어 객체지향적 프로그래밍에 대한 학습또한 할수 있었던 파트다.
728x90
728x90

큐(Queue)

1.구조

  • 가장먼저 넣은 데이터를 가장먼저 꺼낼수 있는 구조
    • 음식점에서 가장먼저 줄을 선 사람이 가장 먼저 음식점에 입장하는것
    • FIFO(First In, First Out)또는 LILO(Last-In, Last-Out)방식으로 스택과 꺼내는 순서가 반대

2.알아둘 용어

  • FIFO
  • Enqueue: 큐에 데이터를 넣는 용어
  • Dequeue: 큐에서 데이터를 꺼내는 용어

3.파이썬 queue 라이브러리 활용해서 큐 자료 구조 사용하기

#일반적인 큐 사용(fifo)
import queue

data_queue = queue.Queue()
data_queue.put("func")
data_queue.put(1)
data_queue.get() # func 출력
data_queue.get() # 1 출력
#들어간 순서대로 출력됨 FIFO

#LifoQueue(Lifo(Lastin,Firstout)) 
import queue
data_queue = queue.LifoQueue()
data_queue.put(123)
data_queue.put(456)
data_queue.get() # 456출력
data_queue.get() # 123출력
#나중에 들어간 456출력 LIFO


#PriorityQueue(우선순위에 따라추출중요!!)
import queue
data_queue = queue.PriorityQueue()
data_queue.put((10,"korea"))
data_queue.put((5,32))
data_queue.put((7,"china"))
data_queue.get() # 32출력
#가장 우선순위가 높은 32가 출력됨

4.직접 dequeue, inqueue구현해보기

#dequeue, inqueue 구현
queue_list = list()

def enqueue(data):
    queue_list.append(data)
    
def dequeue():
    data = queue_list[0]
    del queue_list[0]
    return data

 

스택(stack)

1.구조

  • 스택은 LIFO(Last In, First Out) 또는 FILO(First In, Last Out) 데이터관리 방식을 따름
    • LIFO: 마지막에 넣은 데이터를 가장 먼저 추출하는 데이터 관리 정책
    • FILO: 처음에 넣은 데이터를 가장 마지막에 추출하는 데이터 관리 정책
  • 대표적인 스택의 활용
    • 컴퓨터 내부의 프로세스 구조의 함수 동작 방식
    • def recursive(data):
          if data < 0:
              print("ended")
          else:
              print(data)
              recursive(data-1)
              print('returned',data)
      recursive(3)
      
      #결과
      # 3
      # 2
      # 1
      # 0
      # ended
      # returned 0
      # returned 1
      # returned 2
      # returned 3
      
      # recursive(data-1)의 종결과 같은 ended가 출력된이후 
      # 쌓여있는 returned 출력문을 가장 늦게 들어왔지만 0부터 출력해냄

2.알아둘 용어

  • push():데이터를 스택에 넣기
  • pop():데이터를 스택에서 꺼내기

3.스택의 장단점

  • 장점
    • 구조가 단순해서 구현이 쉽다.
    • 데이터 저장/읽기 속도가 빠르다.
  • 단점
    • 데이터 최대 갯수를 미리 정해야 한다.(파이썬의 경우 재귀함수는 1000번까지 호출가능)
    • 저장공간의 낭비가 발생할 수 있다.(미리 최대 개수만큼 저장 공간을 확보해야함)
  • 스택은 단순하고 빠른 성능을 위해 사용되므로, 보통 배열 구조를 활용해서 구현하는것이 일반적임.

4. 파이선 리스트 기능에서 제공하는 메서드 스택

  • append(push), pop
  • data_stack = list()
    data_stack.append(1)
    data_stack.append(2) # [1,2]
    data_stack.pop() # 2 출력 [1]

5.직접 push, pop 구현해보기

stack_list =list()
def push(data):
    stack_list.append(data)
    
def pop():
    data = stack_list[-1]
    del stack_list[-1]
    return data
728x90
728x90

1.자료구조란?

  • 용어: 자료구조, 데이터구조, datastructure
  • 대량의 데이터를 효율적으로 관리할 수 있는 데이터의 구조를 의미
  • 코드상에서 효율적으로 데이터를 처리하기 위해, 데이터 특성에 따라, 체계적으로 데이터를 구조화해야함
    • 어떤 데이터 구조를 사용하느냐에 따라 코드 효율이 달라짐
  • 효율적으로 데이터를 관리하는 예
    • 우편번호: 5자리 우편번호로 국가의 기초구역을 제공
    • 학생관리: 학년, 반, 번호를 학생에게 부여해서, 학생부를 관리
  • 대표적인 자료구조
    • 배열, 스택, 큐, 링크드 리스트, 해쉬 테이블, 힙등

2.알고리즘이란?

  • 용어: 알고리즘, algorithm
  • 어떤 문제를 풀기위한 절차/방법
  • 어떤 문제에 대해 특정한 '입력'을 넣으면, 원하는 '출력'을 얻을 수 있도록 만드는 프로그래밍
  • 좋은 알고리즘의 요소: 시간복잡도, 데이터 효율성등

3.자료구조와 알고리즘이 중요한 이유

어떤 자료구조와 알고리즘을 쓰느냐에 따라 성능이 전지차다 --> 결국 프로그래밍을 잘 할수 있는 기술과 역량을 익히고, 검증할 수 있음

728x90

'기술 > 알고리즘' 카테고리의 다른 글

자료구조(2)-링크드리스트(LinkedList)  (0) 2022.01.21
자료구조(1)-큐와 스택  (0) 2022.01.19
코딩테스트 준비  (0) 2022.01.19
그리디(2):큰 수의 법칙  (0) 2021.05.22
그리디(1): 거스름돈  (0) 2021.05.21
728x90

코딩테스트 문제를 마구잡이식으로 풀다 보니 아무래도 자료구조/ 알고리즘 관련 면접에서 막힌 경험이 생겼다.. 그리하여 남는 시간동안 자료구조/알고리즘 이론을 좀더 튼튼히 준비한후 동시에 코딩테스트 문제를 풀어보려한다.

 

4군데의 기업에서코딩테스트를 봤는데 2군데 합격, 2군데 불합격이떳다ㅎ... 대부분 유형은 프로그래머스, 백준과 같은 알려진 사이트에서의 문제, sql문제, restapi문제였고 경험은 없지만 지원하는 회사가 사용하는 프레임워크로 시험을 치는 회사가 있다고 했다. 약 2개월동안 좀 빡쌔게 기본을 다시 복습한뒤 이후부턴 여러 회사에 지원해보며 코딩테스트에 모두합격할수 있도록 대비해야겠다.

 

공부 환경은 유명한 아나콘다 환경에서 준비할예정!

728x90
728x90

1.이미지란?

도커에서 서비스 운영에 필요한 서버 프로그램, 소스코드 및 라이브러리, 컴파일된 실행 파일을 묶는 형태를 Image라고 한다. 도커의 실행은 프로세스 실행을 하는것이므로 이 프로세스를 실행하기 위한 모든 파일과 설정값을 지닌것으로, 도커의 주체 즉, 실행할 파일이라고 생각하면 된다. 이미지 파일로 설정할수 있는것들은 mysql, ubuntu, nginx등 이미 만들어져 있는 공식적인 이미지 같은경우, 도커허브(https://hub.docker.com/)에서 모두 확인가능하며 깃허브에 코드를 올리는것과 마찬가지로 개개인이 만든이미지를 업로드하고 공유할수 있다. 그리고 외적으로는 개개인이 새롭게 자신만의 프로젝트를 올릴때는 깃허브와 같은 소스공유 방법을 통해 이미지를 빌드 할수 있다.

 

2.이미지 만들기

docker build -t corin2/testimage:ver1 .

-docker build -t : 도커 이미지 생성 명령어

-corin2 : 이미지를 생성한 사람의 이름

-testimage : 이미지 이름

-:ver1 : 태그 즉, 버전으로 활용가능

-. : 빌드 컨텍스트 위치로 통상적으로 현재위치인 .을 사용하나 필요에따라 다른 디렉터리를 지정하여도 문제없다.

추가로, .dockerignore파일또한 생성가능한데 .gitignore와 같은 역할로 민감한 정보를 가리는것 외에도 빌드시에 가상환경과 같은 부분을 같이 빌드하지 않기위해서도 사용된다.

 

즉, 위 명령어를 통해 생성된 이미지로 도커를 실행시킬수 있는것이다. 이미지는 통상적으로 Dockerfile스크립트 파일을 생성해 실행하는데 Dockerfile에 들어가는 명령어는 아래와 같다.

3.Dockerfile 명령어

FROM 기본이미지
RUN 쉘 명령어 실행
CMD 컨테이너 기본 실행 명령어
EXPOSE 오픈되는 포트 정보
ENV 환경변수 설정
ADD 파일 또는 디렉터리 추가
COPY 파일 또는 디렉터리 추가
ENTRYPOINT 컨테이너 기본 실행 명령어
VOLUME 외부 마운트 포인트 생성
WORKDIR 작업 디렉토리 설정
ARGS 빌드타임 환경변수 설정
LABEL  key - value데이터
ONBUILD 다른 빌드의 베이스로 사용될때 사용하는 명령어
USER RUN, CMD, ENTRYPOINT를 실행하는 사용자

4.활용

도커 이미지 생성같은경우는 작업 환경에서 직접 빌드하는 방식도 있지만 주로 깃허브에서 소스를 가져와 빌드하는 방법이다. 이방법같은경우, 다음 목차에서 간단한 프로젝트를 가져와 빌드하도록 해보겠다.

 

ref. 인프런 강의. 초보를 위한 도커 안내서를 보고 참고하여 정리하였습니다.

 

Docker - 도커란 무엇인가

도커, 도커를 사용하는 이유, 도커의 특징 이해

wooody92.github.io

 

 

초보를 위한 도커 안내서 - 인프런 | 강의

도커를 1도 모르는 입문자, 초보자분들을 위한 도커 안내서 입니다. 복잡한 내용을 제외하고 도커가 왜 인기가 많고 어떻게 사용하는지 빠르게 익힐 수 있도록 집중하였습니다., 데브옵스 입문

www.inflearn.com

 

728x90

'기술 > Devops' 카테고리의 다른 글

aws(2)VPC(Virtual Private Cloud)  (0) 2022.04.19
aws(1)S3(Simple Storage Services)  (0) 2022.04.19
도커(3)-도커 컴포즈  (0) 2022.01.17
도커(2)-도커 설치와 실행  (0) 2022.01.17
도커(1)-도커란?  (1) 2022.01.13
728x90

1.도커 컴포즈란?

일반적인 시스템은 단일 애플리케이션으로 구동이 되지 않습니다. 여러 개의 애플리케이션이 서로 의존성 있게 구성되어 시스템이 이뤄져 있습니다. 그렇다면 흔히 하나의 컨테이너가 하나의 애플리케이션을 담당한다고 하면 여러 개의 컨테이너가 필요로 합니다. 이때 필요한 기술이 도커 컴포즈(Docker Compose)입니다. 도커 컴포즈는 yaml 포맷으로 작성되며 여러 개의 컨테이너의 실행을 한 번에 관리를 할 수 있게 해 줍니다.

2.도커 컴포즈 설치

sudo curl -L "https://github.com/docker/compose/releases/download/1.26.0/
docker-compose-$(uname -s)

3.도커 컴포즈 실행과 종료

-up명령어: 컨테이너 실행

docker-compose up -d

-down명령어: 종료

docker-compose down

4.도커 컴포즈 문법

version: '2' 
services: 
 db: 
   image: mysql:5.7 
   volumes: 
     -./mysql:/var/lib/mysql 
   restart: always 
   environment: 
     MYSQL_ROOT_PASSWORD: wordpress 
     MYSQL_DATABASE: wordpress 
     MYSQL_USER: wordpress 
     MYSQL_PASSWORD: wordpress
 wordpress: 
   image: wordpress:latest 
   volumes: 
     -./wp:/var/www/html 
   ports: 
     -"8000:80" 
   restart: always 
   environment: 
     WORDPRESS_DB_HOST: db:3306 
     WORDPRESS_DB_PASSWORD: wordpress

-version: docker-compose.yml 파일의 명세 버전

version: '2'

-services: 실행할 컨테이너 정의, docker run --name wordpress과 같다고 생각할 수 있음

services:
 db:
 ...
 wordpress:
 ...

-image: 실행할 이미지 태그부분에 버전기입을안할시 자동으로 lastest버전으로 실행

services:
 wordpress:
 image: wordpress:sample

-ports: 컨테이너와 연결할 포트 {호스트 포트}:{컨테이너 포트}

services:
 db:
   ...
   ports:
     - "8000:8000"

-environment: 컨테이너에서 사용할 환경변수 - {환경변수 이름}:{값}

services:
 mysql:
 ...
   environment:
   - MYSQL_ROOT_PASSWORD=somewordpress: '3'

-volumes: 마운트하려는 디렉터리 - {호스트 디렉터리}:{컨테이너 디렉터리}

services:
 django:
 ...
   volumes:
     - ./app:/app

-build: 이미지를 자체 빌드 시 사용 - image속성 대신 사용

django:
 build:
   context: .
   dockerfile: ./compose/django/Dockerfile-dev

그외 logs, stop, start와 같은 기본 명령어는 도커 명령어와 동일!!

 

ref. 인프런 강의. 초보를 위한 도커 안내서를 보고 참고하여 정리하였습니다.

 

Docker - 도커란 무엇인가

도커, 도커를 사용하는 이유, 도커의 특징 이해

wooody92.github.io

 

 

초보를 위한 도커 안내서 - 인프런 | 강의

도커를 1도 모르는 입문자, 초보자분들을 위한 도커 안내서 입니다. 복잡한 내용을 제외하고 도커가 왜 인기가 많고 어떻게 사용하는지 빠르게 익힐 수 있도록 집중하였습니다., 데브옵스 입문

www.inflearn.com

 

728x90

'기술 > Devops' 카테고리의 다른 글

aws(2)VPC(Virtual Private Cloud)  (0) 2022.04.19
aws(1)S3(Simple Storage Services)  (0) 2022.04.19
도커(4)-이미지  (0) 2022.01.19
도커(2)-도커 설치와 실행  (0) 2022.01.17
도커(1)-도커란?  (1) 2022.01.13

+ Recent posts