bong-u/til

๐Ÿ  home ๐Ÿˆ repository ๐Ÿ“ก rss
new RAG ์ด๋ก  ์ •๋ฆฌ + OpenSearch
๐Ÿค– ์ธ๊ณต์ง€๋Šฅ
RAG (Retrieval-Augmented Generation) RAG๋Š” ๊ฒ€์ƒ‰๊ณผ ์ƒ์„ฑ์„ ๊ฒฐํ•ฉํ•œ ๋ชจ๋ธ๋กœ, ๊ฒ€์ƒ‰์„ ํ†ตํ•ด ์–ป์€ ์ •๋ณด๋ฅผ ๋ฐ”ํƒ•์œผ๋กœ ์ƒ์„ฑ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ชจ๋ธ LLM์˜ ๋ฌธ์ œ์  ํ• ๋ฃจ์‹œ๋„ค์ด์…˜: ์ƒ์„ฑ ๋ชจ๋ธ์ด ํ›ˆ๋ จ ๋ฐ์ดํ„ฐ์— ์—†๋Š” ๋‚ด์šฉ์„ ์ƒ์„ฑํ•˜๋Š” ํ˜„์ƒ ์ตœ์‹ ์˜ ์‘๋‹ต์„ ๊ธฐ๋Œ€ํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์˜ค๋ž˜๋˜์—ˆ๊ฑฐ๋‚˜ ์ผ๋ฐ˜์ ์ธ ์ •๋ณด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฌธ์ œ ์‹ ๋ขฐํ•  ์ˆ˜ ์—†๋Š” ์ถœ์ฒ˜๋กœ๋ถ€ํ„ฐ ์ •๋ณด๋ฅผ ์ƒ์„ฑํ•˜๋Š” ๋ฌธ์ œ RAG๋Š” ์œ„์—์„œ ์„œ์ˆ ํ•œ LLM ๋ฌธ์ œ์˜ ์ผ๋ถ€๋ฅผ ํ•ด๊ฒฐํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์ˆ˜๋‹จ์ด๋‹ค. OpenSearch OpenSearch๋Š” ์˜คํ”ˆ์†Œ์Šค ๊ฒ€์ƒ‰ ๋ฐ ๋ถ„์„ ์—”์ง„์œผ๋กœ, ์—˜๋ผ์Šคํ‹ฑ์„œ์น˜์˜ ํฌํฌ ๋ฒ„์ „ ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค : ๋ฒกํ„ฐ ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜๊ณ  ์ฟผ๋ฆฌํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค ์ฃผ์š” ๊ธฐ๋Šฅ ๋ถ„์‚ฐ ๊ฒ€์ƒ‰ ๋ฐ ๋ถ„์„ ๋ณด์•ˆ ์‹œ๊ฐํ™”์™€ ๋Œ€์‹œ๋ณด๋“œ ์ง€์› index์™€ document index : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค document : ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ €์žฅ๋˜๋Š” ๋ฐ์ดํ„ฐ ๋ถ„์„ ๋ถ„์„๊ธฐ Analyzer (Character Filter + Tokenizer + Token Filter) ํ…์ŠคํŠธ๋ฅผ ํ† ํฐํ™”ํ•˜๊ณ  ํ•„ํ„ฐ๋งํ•˜๋Š” ๊ณผ์ •์„ ์ˆ˜ํ–‰ ๋ถ„์„ ๊ณผ์ • Character Filter ํŠน์ • ๋ฌธ์ž๋ฅผ ์ œ๊ฑฐํ•˜๊ฑฐ๋‚˜ ๋ณ€๊ฒฝํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ Tokenizer ๊ธฐ๋ณธ์ ์œผ๋กœ ๊ณต๋ฐฑ์„ ๊ธฐ์ค€์œผ๋กœ ํ…์ŠคํŠธ๋ฅผ ๋ถ„๋ฆฌ Token Filter ํ† ํฐ์„ ์ถ”๊ฐ€ํ•˜๊ฑฐ๋‚˜ ์ œ๊ฑฐํ•˜๋Š” ๋“ฑ์˜ ์ž‘์—…์„ ์ˆ˜ํ–‰ OpenSearch์—์„œ ์ง€์›ํ•˜๋Š” ์š”์†Œ Tokenizer Standard Tokenizer : ๊ณต๋ฐฑ์„ ๊ธฐ์ค€์œผ๋กœ ํ…์ŠคํŠธ๋ฅผ ๋ถ„๋ฆฌ, ๋ฌธ์žฅ ๋ถ€ํ˜ธ ์‚ญ์ œ Letter Tokenizer : ๋ฌธ์ž๋ฅผ ๊ธฐ์ค€์œผ๋กœ ํ…์ŠคํŠธ๋ฅผ ๋ถ„๋ฆฌ Whitespace Tokenizer : ๊ณต๋ฐฑ์„ ๊ธฐ์ค€์œผ๋กœ ํ…์ŠคํŠธ๋ฅผ ๋ถ„๋ฆฌ Ngram Tokenizer : ๋ถ€๋ถ„ ๋ฌธ์ž์—ด๋กœ ํ…์ŠคํŠธ๋ฅผ ๋ถ„๋ฆฌ Token Filter Standard Token Filter : ์•„๋ฌด๊ฒƒ๋„ ํ•˜์ง€ ์•Š์Œ Lowercase Token Filter : ํ…์ŠคํŠธ๋ฅผ ์†Œ๋ฌธ์ž๋กœ ๋ณ€ํ™˜ Synonym Token Filter : ๋™์˜์–ด ์ฒ˜๋ฆฌ Analyzer Standard Analyzer : Standard Tokenizer + Standard Token Filter Simple Analyzer : Letter Tokenizer + Lowercase Token Filter Whitespace Analyzer : Whitespace Tokenizer + Lowercase Token Filter OpenSearch ์ ‘๊ทผ์„ ์œ„ํ•œ cURL ๋ช…๋ น์–ด ์ธ๋ฑ์Šค ์กฐํšŒ 1curl -X GET -u {username}:{password} \ 2"http://localhost:9200/_cat/indices" ํŠน์ • ์ธ๋ฑ์Šค ์กฐํšŒ 1curl -X GET -u {username}:{password} \ 2"http://localhost:9200/{index_name}" ์ „์ฒด ๊ฒ€์ƒ‰ ๊ฒฐ๊ณผ ์กฐํšŒ 1curl -X GET -u {username}:{password} \ 2"http://localhost:9200/{index_name}/_search" ํŠน์ • ๊ฒ€์ƒ‰์–ด๋กœ ๊ฒ€์ƒ‰ํ•œ ๊ฒฐ๊ณผ ์กฐํšŒ 1curl -X GET -u {username}:{password} \ 2"http://localhost:9200/{index_name}/_search" \ 3-H "Content-Type: application/json" \ 4-d '{"query": {"match": {"field": "value"}}}' ์ธ๋ฑ์Šค ์‚ญ์ œ 1curl -X DELETE -u {username}:{password} \ 2"http://localhost:9200/{index_name}"
new OpenSearch๋ฅผ ํ™œ์šฉํ•œ RAG ์‹ค์Šต
๐Ÿค– ์ธ๊ณต์ง€๋Šฅ
๋ฐฐ๊ฒฝ ํ…Œ์ปค ๋ถ€ํŠธ์บ ํ”„์—์„œ ํŒ€ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ ์ค‘์ด๋‹ค. ์šฐ๋ฆฌ ํŒ€์˜ ์ฃผ์ œ๋Š” ํŠน์ • ์ธ๋ฌผ์—๊ฒŒ ์ƒ๋‹ด์„ ๋ฐ›๋Š” ๊ฒƒ ๊ฐ™์€ ๋Œ€ํ™”๋ฅผ ํ•  ์ˆ˜ ์žˆ๋Š” ์ฑ—๋ด‡์„ ๋งŒ๋“œ๋Š” ๊ฒƒ์ด๋‹ค. ์ด๋ฅผ ์œ„ํ•ด ํŠน์ • ์ธ๋ฌผ์ด ํ–ˆ๋˜ ๋ง์„ ๋ชจ์•„ ๋ฐ์ดํ„ฐ์…‹์œผ๋กœ ๋งŒ๋“ค๊ณ  ์ด๋ฅผ RAG ๋ชจ๋ธ์— ์ ์šฉ์‹œํ‚ค๋ ค๊ณ  ํ•œ๋‹ค. ์ˆœ์„œ ์ผ๋ก  ๋จธ์Šคํฌ๊ฐ€ TED์—์„œ ํ•œ ์ธํ„ฐ๋ทฐ๋ฅผ ํ…์ŠคํŠธ๋กœ ๊ฐ€์ ธ์˜จ๋‹ค. OpenSearch ๋„์ปค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์‹คํ–‰ํ•œ๋‹ค. ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ๋ฅผ ์ž„๋ฒ ๋”ฉํ•ด์„œ OpenSearch์— ์ €์žฅํ•œ๋‹ค. RAG ๋ชจ๋ธ์ด OpenSearch๋ฅผ ์ฟผ๋ฆฌํ•˜์—ฌ ๋Œ€๋‹ต์„ ์ƒ์„ฑํ•œ๋‹ค. 1. ์ผ๋ก  ๋จธ์Šคํฌ ์ธํ„ฐ๋ทฐ ํ…์ŠคํŠธ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ ํŠœ๋ธŒ์—์„œ “์Šคํฌ๋ฆฝํŠธ ๋ณด๊ธฐ"๋ฅผ ํ†ตํ•ด ์ธํ„ฐ๋ทฐ ์ž๋ง‰์„ ๊ฐ€์ ธ์˜จ๋‹ค. 122:03 2EM: ์ด ํฐ ํŠธ๋Ÿญ์„ ๋ชฐ๋ฉด์„œ ๋ง๋„ ์•ˆ๋˜๋Š” ์›€์ง์ž„์„ ๋ณด์˜€์ฃ . 3CA: ์•„์ฃผ ๋ฉ‹์ง€๋„ค์š”. ์ž, ๊ทธ๋Ÿผ ์ •๋ง ๊ต‰์žฅํ•œ ์‚ฌ์ง„์—์„œ 422:09 5์กฐ๊ธˆ์€ ๋œ ๊ต‰์žฅํ•œ ์‚ฌ์ง„์„ ๋ณด์ฃ . "์œ„๊ธฐ์˜ ์ฃผ๋ถ€๋“ค"์ธ๊ฐ€์—์„œ ๋‚˜์˜ค๋Š” ๊ท€์—ฌ์šด ์ง‘ ์‚ฌ์ง„์ธ๋ฐ์š”. 622:15 7์ด๊ฒŒ ๊ฐ‘์ž๊ธฐ ์™œ ๋‚˜์˜จ๊ฑฐ์ฃ ? 8... ์ผ๋ก  ๋จธ์Šคํฌ๊ฐ€ ํ•œ ๋ง๋งŒ ์†์ˆ˜ ์ •๋ฆฌํ•œ๋‹ค. 1๋„ค. ์ œ ์Šค์Šค๋กœ๋„ ๊ทธ ์งˆ๋ฌธ์„ ์ž์ฃผ ํ•˜๋Š” ํŽธ์ž…๋‹ˆ๋‹ค. 2์ €ํฌ๋Š” LA์˜ ์ง€ํ•˜์— ๊ตฌ๋ฉ์„ ๋‚ด๋ ค๊ณ  ํ•˜๋Š”๋ฐ์š”. ์ด๋Š” ๊ตํ†ต ์ฒด์ฆ์„ ์™„ํ™”์‹œํ‚ค๊ธฐ ์œ„ํ•œ 33์ฐจ์› ๋„คํŠธ์›Œํฌ์˜ ํ„ฐ๋„์ด ๋  ์ˆ˜๋„ ์žˆ๋Š” ์‹œ๋ฐœ์ ์„ ๋งŒ๋“ค๊ธฐ ์œ„ํ•จ์ž…๋‹ˆ๋‹ค. 4๊ตํ†ต ์ฒด์ฆ์€ ์˜ค๋Š˜๋‚  ์šฐ๋ฆฌ์˜ ์˜ํ˜ผ์„ ํƒˆํƒˆ ํ„ฐ๋Š” ๋ฌธ์ œ ์ค‘์˜ ํ•˜๋‚˜์ž…๋‹ˆ๋‹ค. 5์„ธ๊ณ„ ๋ชจ๋“  ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์˜ํ–ฅ์„ ๋ผ์น˜๊ณ  ์žˆ์ฃ . ์ธ์ƒ์—์„œ ๋„ˆ๋ฌด๋„ ๋งŽ์€ ๋ถ€๋ถ„์„ ๊ฐ€์ ธ๊ฐ‘๋‹ˆ๋‹ค. 6... 2. OpenSearch ๋„์ปค ์ปจํ…Œ์ด๋„ˆ ์‹คํ–‰ 1docker create -it -p 9200:9200 -p 9600:9600 -e OPENSEARCH_INITIAL_ADMIN_PASSWORD={password} -e "discovery.type=single-node" -v opensearch_vol:/usr/share/opensearch/data --name opensearch opensearchproject/opensearch ์„ค๋ช… -p 9200:9200 : OpenSearch HTTP ํฌํŠธ -p 9600:9600 : OpenSearch ๋ชจ๋‹ˆํ„ฐ๋ง ํฌํŠธ -e OPENSEARCH_INITIAL_ADMIN_PASSWORD={password} : ์ดˆ๊ธฐ ๋น„๋ฐ€๋ฒˆํ˜ธ ์„ค์ • -e “discovery.type=single-node” : ๋‹จ์ผ ๋…ธ๋“œ๋กœ ์‹คํ–‰ -v opensearch_vol:/usr/share/opensearch/data : ๋ฐ์ดํ„ฐ ๋ณผ๋ฅจ ๋งˆ์šดํŠธ SSL ์˜ค๋ฅ˜ ๋ฐœ์ƒ๊ณผ ํ•ด๊ฒฐ ํ•˜์ง€๋งŒ ์œ„ ๋ช…๋ น์–ด๋กœ ์‹คํ–‰ํ•˜๋ฉด ์ปจํ…Œ์ด๋„ˆ ๋‚ด๋ถ€์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค 12024-07-05 22:15:12 Caused by: io.netty.handler.ssl.NotSslRecordException: not an SSL/TLS record: ... 22024-07-05 22:15:12 at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1314) ~[netty-handler-4.1.110.Final.jar:4.1.110.Final] 32024-07-05 22:15:12 at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1387) ~[netty-handler-4.1.110.Final.jar:4.1.110.Final] 42024-07-05 22:15:12 at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:530) ~[netty-codec-4.1.110.Final.jar:4.1.110.Final] 52024-07-05 22:15:12 at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:469) ~[netty-codec-4.1.110.Final.jar:4.1.110.Final] 62024-07-05 22:15:12 ... 16 more ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„์ด ๊ธธ์ง€ ์•Š๊ณ , ํ•ด๋‹น ํฌํŠธ๋Š” ์™ธ๋ถ€์— ๋…ธ์ถœํ•  ํ•„์š”๊ฐ€ ์—†์œผ๋ฏ€๋กœ SSL์„ ๋„๊ณ  ์‹คํ–‰ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ํ•ด๊ฒฐํ•˜์˜€๋‹ค. 1/usr/share/opensearch/config/opensearch.yml 2# ๋ณ€๊ฒฝ ์ „ 3plugins.security.ssl.http.enabled: true 4# ๋ณ€๊ฒฝ ํ›„ 5plugins.security.ssl.http.enabled: false 3. ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ ์ž„๋ฒ ๋”ฉ ๋ฐ OpenSearch์— ์ €์žฅ RAG ์„ธ์…˜์„ ํ•ด์ฃผ์‹  ๋ฉ˜ํ† ๋‹˜์ด ์งœ์ค€ ์ฝ”๋“œ๋ฅผ ์ ๊ทน! ์ฐธ๊ณ ํ•˜์—ฌ ์ž‘์„ฑํ•˜์˜€๋‹ค. OpenSearch ์ธ๋ฑ์Šค ์ƒ์„ฑ 1from opensearchpy import OpenSearch 2import torch 3from transformers import AutoTokenizer, AutoModel 4from langchain.text_splitter import RecursiveCharacterTextSplitter 5from langchain_community.document_loaders import TextLoader 6from langchain_community.vectorstores import OpenSearchVectorSearch 7 8INDEX_NAME = "elon_musk" 9FILE_NAME = "ted_elon_musk_script.txt" 10 11## OpenSearch ์—ฐ๊ฒฐ ์„ค์ • 12client = OpenSearch( 13 hosts=[{"host": "localhost", "port": 9200}], http_auth=("admin", {password}) 14) 15 16## ํ…์ŠคํŠธ ๋ฐ์ดํ„ฐ ๋ถˆ๋Ÿฌ์˜ค๊ธฐ 17loader = TextLoader(file_path=FILE_NAME, encoding="utf-8") 18docs = loader.load() 19 20text_splitter = RecursiveCharacterTextSplitter( 21 chunk_size=100, 22 chunk_overlap=0, 23 separators=["\n"], 24 length_function=len, 25) 26 27documents = text_splitter.split_documents(docs) 28 29# print(documents) 30 31## Embedding ๋ชจ๋ธ ์ •์˜ 32class MyEmbeddingModel: 33 def __init__(self, model_name): 34 self.tokenizer = AutoTokenizer.from_pretrained(model_name) 35 self.model = AutoModel.from_pretrained(model_name) 36 37 def embed_documents(self, doc): 38 inputs = self.tokenizer( 39 doc, return_tensors="pt", padding=True, truncation=True, max_length=512 40 ) 41 42 with torch.no_grad(): 43 outputs = self.model(**inputs) 44 embeddings = outputs.last_hidden_state.mean(dim=1).tolist() 45 46 return embeddings 47 48 def embed_query(self, text): 49 inputs = self.tokenizer( 50 [text], padding=True, truncation=True, return_tensors="pt", max_length=512 51 ) 52 with torch.no_grad(): 53 outputs = self.model(**inputs) 54 embeddings = outputs.last_hidden_state.mean(dim=1).tolist() 55 return embeddings 56 57 58## index ๊ตฌ์กฐ ์ •์˜ 59index_body = { 60 "settings": { 61 "analysis": { 62 "tokenizer": { 63 "nori_user_dict": { 64 "type": "nori_tokenizer", 65 "decompound_mode": "mixed", 66 "user_dictionary": "user_dic.txt", 67 } 68 }, 69 "analyzer": { 70 "korean_anlyzer": { 71 "filter": [ 72 "synonym", "lowercase", 73 ], 74 "tokenizer": "nori_user_dict", 75 } 76 }, 77 "filter": { 78 "synonym" :{ 79 "type": "synonym_graph", 80 "synonyms_path" : "synonyms.txt" 81 } 82 } 83 } 84 } 85} 86 87## Embedding ๋ชจ๋ธ ์ƒ์„ฑ 88my_embedding = MyEmbeddingModel("monologg/kobert") 89 90## OpenSearch์— ๋ฐ์ดํ„ฐ ์‚ฝ์ž… 91vector_db = OpenSearchVectorSearch.from_documents( 92 index_name=INDEX_NAME, 93 body=index_body, 94 documents=documents, 95 embedding=my_embedding, 96 op_type="create", 97 opensearch_url="http://localhost:9200", 98 http_auth=("admin", {password}), 99 use_ssl=False, 100 verify_certs=False, 101 ssl_assert_hostname=False, 102 ssl_show_warn=False, 103 bulk_size=1000000, 104 timeout=360000, 105) 106 107result = vector_db.add_documents(documents, bulk_size=1000000) tokenizer๋Š” ํ•œ๊ตญ์–ด๋ฅผ ์ง€์›ํ•˜๋Š” “nori_tokenizer"๋ฅผ ์‚ฌ์šฉํ•˜์˜€๋‹ค. embedding ๋ชจ๋ธ์€ ์ €๊ฑฐ ๋ง๊ณ ๋„ ์—ฌ๋Ÿฌ๊ฐ€์ง€๊ฐ€ ์กด์žฌํ•˜๋Š”๋ฐ, ์–ด๋–ค ๋ชจ๋ธ์ด ํ”„๋กœ์ ํŠธ์— ๊ฐ€์žฅ ๋ถ€ํ•ฉํ•˜๋Š” ๋ชจ๋ธ์ธ์ง€๋Š” ์‹คํ—˜์„ ํ•ด๋ณผ ๊ฒƒ์ด๋‹ค. curl์„ ํ†ตํ•ด localhost:9200/elon_musk/_search๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด ์ž„๋ฒ ๋”ฉํ•œ ๋ฐ์ดํ„ฐ๊ฐ€ ์ž˜ ๋“ค์–ด๊ฐ”๋Š”์ง€ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค. 4. RAG ๋ชจ๋ธ์ด OpenSearch๋ฅผ ์ฟผ๋ฆฌํ•˜์—ฌ ๋Œ€๋‹ต ์ƒ์„ฑ 1from langchain.prompts import PromptTemplate 2from langchain.chains import LLMChain 3from langchain_openai import ChatOpenAI 4from opensearchpy import OpenSearch 5import os 6 7INDEX_NAME = "elon_musk" 8 9# ํ™˜๊ฒฝ๋ณ€์ˆ˜ ์„ค์ • 10os.environ["OPENAI_API_KEY"] = {api_key} 11 12llm = ChatOpenAI( 13 model_name="gpt-3.5-turbo", 14) 15 16prompt_template = PromptTemplate( 17 input_variables=["context", "question"], 18 template=""" 19Imagine you are {character_name}, 20a wise and experienced advisor. Given the context: "{context}", 21how would you respond to this inquiry: "{question}"?', 22(in korean) 23""", 24) 25 26 27llm_chain = LLMChain(llm=llm, prompt=prompt_template) 28 29client = OpenSearch( 30 hosts=["http://localhost:9200"], 31 http_auth=("admin", {password}), 32 use_ssl=False, 33 verify_certs=False, 34 ssl_assert_hostname=False, 35 ssl_show_warn=False, 36) 37 38def search_documents(query): 39 search_body = {"query": {"match": {"text": query}}} 40 response = client.search(index=INDEX_NAME, body=search_body) 41 hits = response["`its"]["hits"] 42 return [hit["_source"]["text"] for hit in hits] 43 44if __name__ == "__main__": 45 question = input("Enter your question\n") 46 search_results = search_documents(question) 47 48 print(search_results) 49 50 # context = " ".join(search_results) 51 context = "" 52 53 response = llm_chain.invoke({"character_name": INDEX_NAME, "context": context, "question": question}) 54 55 print (response["text"]) OpenSearch์— ์ €์žฅ๋œ ๋ฐ์ดํ„ฐ๋ฅผ ์ฟผ๋ฆฌํ•˜์—ฌ RAG ๋ชจ๋ธ์— ๋„ฃ์–ด ๋Œ€๋‹ต์„ ์ƒ์„ฑํ•œ๋‹ค. search_documents ํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด OpenSearch์— ์ฟผ๋ฆฌ๋ฅผ ๋ณด๋‚ด๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ context๋กœ ์‚ฌ์šฉํ•œ๋‹ค. ๊ฒฐ๊ณผ ์งˆ๋ฌธ ํ…Œ์Šฌ๋ผ์— ๋Œ€ํ•ด์„œ ์–ด๋–ป๊ฒŒ ์ƒ๊ฐํ•ด? RAG๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ์˜ ๋Œ€๋‹ต ํ…Œ์Šฌ๋ผ๋Š” ํ˜์‹ ์ ์ธ ๊ธฐ์—…์œผ๋กœ์„œ ๋ฏธ๋ž˜๋ฅผ ํ–ฅํ•œ ๋น„์ „์„ ๊ฐ€์ง€๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋“ค์˜ ์ „๊ธฐ ์ž๋™์ฐจ ๊ธฐ์ˆ ๊ณผ ์—๋„ˆ์ง€ ์†”๋ฃจ์…˜์€ ์ „ ์„ธ๊ณ„์ ์œผ๋กœ ์ฃผ๋ชฉ๋ฐ›๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ…Œ์Šฌ๋ผ์˜ ํ˜์‹ ์ ์ธ ์ ‘๊ทผ ๋ฐฉ์‹๊ณผ ์ง€์† ๊ฐ€๋Šฅํ•œ ๋น„์ฆˆ๋‹ˆ์Šค ๋ชจ๋ธ์— ๋Œ€ํ•ด ๋งค์šฐ ๊ธ์ •์ ์œผ๋กœ ์ƒ๊ฐํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. RAG๋ฅผ ์‚ฌ์šฉํ• ๋•Œ ์ ์šฉ๋œ context [‘๊ธธ๊ฒŒ ๊ฐˆ ๊ฒƒ ๊ฐ™์ง€๋Š” ์•Š์•„์š”.\n๊ทธ๋Ÿฌ๋„ค์š”. ์ €๋Š” ์ตœ๋Œ€ํ•œ ์˜ค๋žซ๋™์•ˆ ํ…Œ์Šฌ๋ผ์— ๋จธ๋ฌผ ์ƒ๊ฐ์ด์—์š”.\n๊ทธ๋ฆฌ๊ณ  ์ค€๋น„ ์ค‘์— ์žˆ๋Š” ํฅ๋ฏธ๋กœ์šด ์ผ๋„ ๋งŽ๊ณ ์š”. ์•„์‹œ๋‹ค์‹œํ”ผ, ๋ชจ๋ธ 3์ด ์ถœ์‹œ ์˜ˆ์ •์ด๊ณ ์š”.’, ‘์˜ฌํ•ด ๋ง๊นŒ์ง€ LA์—์„œ ๋‰ด์š•๊นŒ์ง€\n์™„์ „ ์ž์œจ ์ฃผํ–‰์œผ๋กœ ํšก๋‹จํ•˜๋Š” ๊ณ„ํš์— ๋งž์ถฐ์„œ ์ง„ํ–‰ ์ค‘์ด์—์š”.\n์‚ฌ๋žŒ์ด ํ…Œ์Šฌ๋ผ์— ํƒ€์„œ ์šด์ „๋Œ€๋ฅผ ์žก์ง€ ์•Š๊ณ  “๋‰ด์š•"์„ ์ฐ์œผ๋ฉด ๊ทธ๋ฆฌ๋กœ ๊ฐ„๋‹ค๋Š” ๋ง์ด๋„ค์š”.’, ‘๊ธธ๊ฒŒ ๊ฐˆ ๊ฒƒ ๊ฐ™์ง€๋Š” ์•Š์•„์š”.\n๊ทธ๋Ÿฌ๋„ค์š”. ์ €๋Š” ์ตœ๋Œ€ํ•œ ์˜ค๋žซ๋™์•ˆ ํ…Œ์Šฌ๋ผ์— ๋จธ๋ฌผ ์ƒ๊ฐ์ด์—์š”.\n๊ทธ๋ฆฌ๊ณ  ์ค€๋น„ ์ค‘์— ์žˆ๋Š” ํฅ๋ฏธ๋กœ์šด ์ผ๋„ ๋งŽ๊ณ ์š”. ์•„์‹œ๋‹ค์‹œํ”ผ, ๋ชจ๋ธ 3์ด ์ถœ์‹œ ์˜ˆ์ •์ด๊ณ ์š”.’, ‘์˜ฌํ•ด ๋ง๊นŒ์ง€ LA์—์„œ ๋‰ด์š•๊นŒ์ง€\n์™„์ „ ์ž์œจ ์ฃผํ–‰์œผ๋กœ ํšก๋‹จํ•˜๋Š” ๊ณ„ํš์— ๋งž์ถฐ์„œ ์ง„ํ–‰ ์ค‘์ด์—์š”.\n์‚ฌ๋žŒ์ด ํ…Œ์Šฌ๋ผ์— ํƒ€์„œ ์šด์ „๋Œ€๋ฅผ ์žก์ง€ ์•Š๊ณ  “๋‰ด์š•"์„ ์ฐ์œผ๋ฉด ๊ทธ๋ฆฌ๋กœ ๊ฐ„๋‹ค๋Š” ๋ง์ด๋„ค์š”.’] RAG๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ์˜ ๋Œ€๋‹ต ์ €๋Š” ํ…Œ์Šฌ๋ผ๋ฅผ ๋งค์šฐ ๊ธ์ •์ ์œผ๋กœ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ…Œ์Šฌ๋ผ๋Š” ํ˜์‹ ์ ์ธ ๊ธฐ์ˆ ๊ณผ ์ง€์† ๊ฐ€๋Šฅํ•œ ๋ฏธ๋ž˜๋ฅผ ์œ„ํ•œ ๋น„์ „์„ ๊ฐ–์ถ˜ ๊ธฐ์—…์œผ๋กœ์„œ, ์ž์œจ ์ฃผํ–‰ ๊ธฐ์ˆ ์„ ํ†ตํ•ด ์šฐ๋ฆฌ์˜ ์‚ถ์„ ํ˜์‹ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์ „๊ธฐ์ฐจ ์‹œ์žฅ์„ ์„ ๋„ํ•˜๊ณ  ํ™˜๊ฒฝ์— ์นœํ™”์ ์ธ ์ฐจ๋Ÿ‰์„ ์ œ๊ณตํ•˜๋Š” ๋ฉ‹์ง„ ๊ธฐ์—…์ด๋ผ๊ณ  ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ํ…Œ์Šฌ๋ผ์˜ ๋ฏธ๋ž˜๊ฐ€ ๋ฐ๊ณ  ํฅ๋ฏธ๋กœ์šด ์ผ๋“ค์ด ๊ณ„์†ํ•ด์„œ ์ผ์–ด๋‚  ๊ฒƒ์ด๋ผ๊ณ  ๋ฏฟ์Šต๋‹ˆ๋‹ค. ๊ณ ์ฐฐ ํ™•์‹คํžˆ RAG๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š์•˜์„ ๋•Œ๋Š” ๊ฐ๊ด€์ ์ด๊ณ  ์ผ๋ฐ˜์ ์ธ ๋Œ€๋‹ต์„ ํ•˜๋Š” ๋ฐ˜๋ฉด, RAG๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” ํ…Œ์Šฌ๋ผ์— ๋Œ€ํ•ด ๊ธ์ •์ ์ธ ์ผ๋ก  ๋จธ์Šคํฌ์˜ ๋Œ€๋‹ต๊ณผ, ์ž์œจ์ฃผํ–‰ ๊ธฐ์ˆ ์„ ์–ธ๊ธ‰ํ–ˆ๋‹ค๋Š” ๊ฒƒ์„ ๋ฐ˜์˜ํ•˜์—ฌ ๋Œ€๋‹ต์„ ์ƒ์„ฑํ•˜์˜€๋‹ค.
new ์ปดํŒŒ์ผ๋Ÿฌ๊ฐœ๋ก 
๐Ÿซ ํ•™๊ณผ ๊ณต๋ถ€
๊ฐœ์š” ์ปดํ“จํ„ฐ์™€ ์ธ๊ฐ„์ด ์†Œํ†ตํ•˜๋Š” ๋ฐฉ๋ฒ• ์–ด์…ˆ๋ธ”๋ฆฌ์–ด ์–ด์…ˆ๋ธ”๋ฆฌ์–ด์˜ ๋ฒˆ์—ญ๊ธฐ๋Š” ์–ด์…ˆ๋ธ”๋Ÿฌ(Assembler)๋ผ๊ณ  ํ•œ๋‹ค cpu์นฉ์…‹์ด ๋ฐ”๋€”๋•Œ๋งˆ๋‹ค ์–ด์…ˆ๋ธ”๋ฆฌ์–ด๊ฐ€ ๋ฐ”๋€๋‹ค ๊ณ ๊ธ‰์–ธ์–ด ๊ณ ๊ธ‰์–ธ์–ด์˜ ๋ฒˆ์—ญ๊ธฐ๋Š” ์ปดํŒŒ์ผ๋Ÿฌ(Compiler)๋ผ๊ณ  ํ•œ๋‹ค ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์ •ํ™•ํ•œ ์ •์˜ ์–ด๋–ค ์–ธ์–ด๋กœ ์“ฐ์—ฌ์ง„ ํ”„๋กœ๊ทธ๋žจ์„ ๊ฐ™์€ ์—ญํ• ์˜ ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ๋ฐ”๊ฟ”์ฃผ๋Š” ํ”„๋กœ๊ทธ๋žจ 1952๋…„ ๊ทธ๋ ˆ์ด์Šค ํ˜ธํผ(Grace Hopper)๊ฐ€ UNIVAC์šฉ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์–ธ์–ด A-0 ์ปดํŒŒ์ผ๋Ÿฌ๋ฅผ ์ œ์ž‘ ์ปดํŒŒ์ผ๋Ÿฌ vs ์ธํ„ฐํ”„๋ฆฌํ„ฐ ํ”„๋กœ๊ทธ๋žจ ์ฒ˜๋ฆฌ๊ณผ์ • ์ปดํŒŒ์ผ๋Ÿฌ์˜ ์ฒ˜๋ฆฌ ๊ณผ์ • Lexical analysis (์–ดํœ˜ ๋ถ„์„) token์„ ์ƒ์„ฑํ•˜๋Š”์ผ, token์€ ์–ดํœ˜์˜ ์ตœ์†Œ ๋‹จ์œ„ Syntax analysis (๊ตฌ๋ฌธ ๋ถ„์„) token์„ ์ฝ์–ด์„œ ์˜ค๋ฅ˜๋ฅผ ๊ฒ€์ƒ‰, ๊ตฌ๋ฌธ ๊ตฌ์กฐ๋ฅผ ๋งŒ๋“ ๋‹ค (์ฃผ๋กœ ํŠธ๋ฆฌํ˜•ํƒœ) Semantic analysis (์˜๋ฏธ ๋ถ„์„) type checking Intermediate code generation (์ค‘๊ฐ„ ์ฝ”๋“œ ์ƒ์„ฑ) ์ค‘๊ฐ„ ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ Code optimization (์ฝ”๋“œ ์ตœ์ ํ™”) ์ค‘๊ฐ„ ์ฝ”๋“œ๋ฅผ ๋” ํšจ์œจ์ ์œผ๋กœ ๋ณ€ํ™˜ Code generation (์ฝ”๋“œ ์ƒ์„ฑ) ๋ชฉ์  ์ฝ”๋“œ ์ƒ์„ฑ Lexical analysis (์–ดํœ˜ ๋ถ„์„) token : ๋ฌธ๋ฒ•์ ์œผ๋กœ ์˜๋ฏธ์žˆ๋Š” ์ตœ์†Œ ๋‹จ์œ„ FSA (Finite State Automata, ์œ ํ•œ ์ƒํƒœ ์˜คํ† ๋งˆํƒ€) token์„ ์ธ์‹ํ•˜๋Š” ๋ฐฉ๋ฒ• ์‹œ์ž‘ ์ƒํƒœ ํ•œ ๊ฐœ์™€ ๋ ์ƒํƒœ ์—ฌ๋Ÿฌ ๊ฐœ๋ฅผ ๊ฐ€์ง DFA (Deterministic Finite Automata) FSA์˜ ํ•œ ์ข…๋ฅ˜ ๊ฐ ์ƒํƒœ์—์„œ ๋ป—์–ด๋‚˜๊ฐ€๋Š” edge๊ฐ€ ํ•˜๋‚˜์”ฉ๋งŒ ์กด์žฌ ฮต๊ฐ€ ๋ถ™์€ edge ์—†์Œ ๋ถ„์„ํ•œ ํ† ํฐ์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ• Lexeme = <ํ† ํฐ๋ฒˆํ˜ธ, ํ† ํฐ ๊ฐ’> ์˜ˆ์‹œ if X < Y … (29, 0) (1, X) (18, 0) (1, Y) … ์‹๋ณ„์ž์˜ ํ† ํฐ๋ฒˆํ˜ธ๋Š” 1๋ฒˆ, ์ƒ์ˆ˜๋Š” 2๋ฒˆ ๋“ฑ์œผ๋กœ ๊ณ ์ • Syntax analysis (๊ตฌ๋ฌธ ๋ถ„์„) token์„ ์ฝ์–ด์„œ ์˜ค๋ฅ˜๋ฅผ ๊ฒ€์ƒ‰, parse tree๋ฅผ ๋งŒ๋“ ๋‹ค CFG (Context Free Grammer) ๊ตฌ๋ฌธ์„ ํ‘œํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ• G = (N, T, P, S) N = nonterminal symbol ์•ŒํŒŒ๋ฒณ ๋Œ€๋ฌธ์ž๋กœ ํ‘œํ˜„ T = terminal symbol (token) ์•ŒํŒŒ๋ฒณ ์†Œ๋ฌธ์ž+์ˆซ์ž, ์—ฐ์‚ฐ์ž, ๊ตฌ๋ถ„์ž, ํ‚ค์›Œ๋“œ ๋“ฑ P = production rule ์˜ˆ) S -> T+T, T -> ‘0’|‘1’|‘2’ S = start symbol L(G) : ์ด ๋ฌธ๋ฒ•์œผ๋กœ ์ƒ์„ฑ๋˜๋Š” ์–ธ์–ด ์—ฌ๋Ÿฌ๊ฐ€์ง€ CFG ํ‘œํ˜„๋ฒ• BNF (Backus-Naur Form) EBNF (Extended BNF) ์œ ๋„ (derivation) ์ƒ์„ฑ ๊ทœ์น™๋ฅผ ์ ์šฉํ•˜์—ฌ ๋ฌธ์žฅ์„ ์ƒ์„ฑํ•˜๋Š” ๊ณผ์ • ์œ ๋„๋ฅผ ํ•˜๋Š” ๊ณผ์ •์—์„œ ํ•˜๋‚˜์”ฉ ๊ณจ๋ผ์„œ ๋ฐ”๊ฟˆ ์œ ๋„ ํŠธ๋ฆฌ : ์œ ๋„ ๊ฒฝ๋กœ๋ฅผ ์ถ”์ƒํ™” ์‹œ์ผœ ํ‘œํ˜„ํ•œ ๊ฒƒ ์ขŒ์ธก ์œ ๋„(leftmost derivation) ๊ฐ€์žฅ ์™ผ์ชฝ์— ์žˆ๋Š” nonterminal์„ ๋จผ์ € ๋Œ€์น˜ ์šฐ์ธก ์œ ๋„(rightmost derivation) ๊ฐ€์žฅ ์˜ค๋ฅธ์ชฝ์— ์žˆ๋Š” nonterminal์„ ๋จผ์ € ๋Œ€์น˜ ๋ชจํ˜ธ์„ฑ (ambiguity) ๋ฌธ๋ฒ• G์— ์˜ํ•ด ์ƒ์„ฑ๋˜๋Š” ์–ด๋–ค ๋ฌธ์žฅ์ด ๋‘๊ฐœ ์ด์ƒ์˜ ์œ ๋„ํŠธ๋ฆฌ๋ฅผ ๊ฐ–๋Š”๋‹ค๋ฉด ๋ฌธ๋ฒ• G๋Š” ๋ชจํ˜ธํ•˜๋‹ค๊ณ  ํ•œ๋‹ค ๋ชจํ˜ธํ•˜์ง€ ์•Š์€ ๋ฌธ๋ฒ•์€ ์ขŒ์ธก ์œ ๋„์™€ ์šฐ์ธก ์œ ๋„๊ฐ€ ๊ฐ™๋‹ค ๋ชจํ˜ธ์„ฑ ํ•ด๊ฒฐ ์—ฐ์‚ฐ์ž ์šฐ์„ ์ˆœ์œ„ ๋„์ž… ๊ฒฐํ•ฉ ๋ฒ•์น™ ๋„์ž… Left Recursion์€ ์ขŒ์ธก ๊ฒฐํ•ฉ์— ์‚ฌ์šฉ ex) A -> A+a | a Right Recursion์€ ์šฐ์ธก ๊ฒฐํ•ฉ์— ์‚ฌ์šฉ ex) A -> a+A | a ๊ตฌ๋ฌธ ๋ถ„์„์˜ 2๊ฐ€์ง€ ๋ฐฉ์‹ top-down, bottom-up Top-down parsing Top-down ๋ฐฉ์‹ ์ขŒ์ธก ์œ ๋„์™€ ๊ฐ™์€ ์ˆœ์„ ์˜ ์ƒ์„ฑ ๊ทœ์น™ ์ ์šฉ backtracking : ์œ ๋„๋œ ๋ฌธ์ž์—ด๊ณผ ์ž…๋ ฅ ๋ฌธ์ž์—ด์ด ๊ฐ™์ง€ ์•Š์œผ๋ฉด ๋‹ค๋ฅธ ์ƒ์„ฑ๊ทœ์น™ ์ ์šฉ Bottom-up ๋ฐฉ์‹ ์šฐ์ธก ์œ ๋„์˜ ์—ญ์ˆœ์˜ ์ƒ์„ฑ ๊ทœ์น™ ์ ์šฉ LL ํŒŒ์‹ฑ ์™ผ์ชฝ->์˜ค๋ฅธ์ชฝ์œผ๋กœ ์ฝ์–ด์„œ ์ขŒํŒŒ์Šค ์ƒ์„ฑ backtracking X, ๋น ๋ฅด๋‹ค ๊ฒฐ์ •์ ์œผ๋กœ ํŒŒ์‹ฑ ์‚ฌ์šฉ๋œ ์ •์˜ ฮต-์ƒ์„ฑ๊ทœ์น™ Nonterminal A๊ฐ€ ฮต๋ฅผ ์œ ๋„ํ•  ์ˆ˜ ์žˆ์œผ๋ฉด A๋ฅผ nullableํ•˜๋‹ค๊ณ  ๋ถ€๋ฅธ๋‹ค lhs, rhs A->XXX์—์„œ lhs๋Š” A, rhs๋Š” XXX โŠ• (Ring Sum) A์— ฮต๊ฐ€ ์žˆ์œผ๋ฉด, AโŠ•B = (A์—์„œ ฮต๋นผ๊ณ  A ํ•ฉ์ง‘ํ•ฉ B) A์— ฮต๊ฐ€ ์—†์œผ๋ฉด, AโŠ•B = A First nonterminal A๋กœ ๋ถ€ํ„ฐ ์œ ๋„๋˜์–ด ์ฒซ๋ฒˆ์งธ๋กœ ๋‚˜ํƒ€๋‚  ์ˆ˜ ์žˆ๋Š” terminal์˜ ์ง‘ํ•ฉ X->Y1Y2Y3์ผ๋•Œ, FIRST(X) = FIRST(X) U FIRST(Y1) โŠ• FIRST(Y2) โŠ• FIRST(Y3) Follow A ๋‹ค์Œ์— ๋‚˜์˜ค๋Š” terminal์˜ ์ง‘ํ•ฉ A->ฮฑBฮฒ, ฮฒ != ฮต ์ผ๋•Œ, FOLLOW(B) = FOLLOW(B) U (FIRST(ฮฒ)-{ฮต}) A->ฮฑB ๋˜๋Š” A->ฮฑBฮฒ, FIRST(ฮฒ)์— ฮต๊ฐ€ ์†ํ•  ๋•Œ, FOLLOW(B) = FOLLOW(B) U FOLLOW(A) LL์กฐ๊ฑด FIRST(ฮฑ)์™€ FIRST(ฮฒ)๊ฐ€ ๊ฒน์น˜๋ฉด ์•ˆ๋œ๋‹ค FIRST(ฮฑ)์— ฮต๊ฐ€ ์žˆ์œผ๋ฉด, FOLLOW(ฮฑ)์™€ FIRST(ฮฒ)๊ฐ€ ๊ฒน์น˜๋ฉด ์•ˆ๋œ๋‹ค LL ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” ๋ฌธ๋ฒ• = LL ํŒŒ์‹ฑ ๋˜๋Š” ๋ฌธ๋ฒ• LL(1) ๋ฌธ๋ฒ• ์ž„์˜์˜ ๋ฌธ๋ฒ•์— ๋Œ€ํ•˜์—ฌ LL ์กฐ๊ฑด์„ ๋งŒ์กฑํ•˜๋Š” CFG 1 : LOOKAHEAD๊ฐ€ 1๊ฐœ๋ผ๋Š” ์˜๋ฏธ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ๊ฒฝ์šฐ LL(1)๋ฌธ๋ฒ•์ด ๋˜์ง€ ์•Š๋Š”๋‹ค ๋ชจํ˜ธํ•œ ๋ฌธ๋ฒ• ์šฐ์„ ์ˆœ์œ„ ์ฃผ๊ธฐ, ๊ฒฐํ•ฉ๋ฒ•์น™ ๋ฐ˜์˜์œผ๋กœ ํ•ด๊ฒฐ left-factoring์ด ๋˜๋Š” ๊ฒฝ์šฐ ๊ณตํ†ต ์•ž๋ถ€๋ถ„์„ ์ƒˆ๋กœ์šด nonterminal๋กœ ๋งŒ๋“ค์–ด ํ•ด๊ฒฐ left-recursiveํ•œ ๊ฒฝ์šฐ ์ง์ ‘ recursion : A -> Aฮต ์ธ๊ฒฝ์šฐ ๊ฐ„์ ‘ recursion : A -> B, B -> A ์ธ๊ฒฝ์šฐ LOOKAHEAD ์–ด๋–ค ๊ทœ์น™์ด ์ ์šฉ๋˜์—ˆ์„๋•Œ ๋งจ ์ฒ˜์Œ ๋‚˜์˜ฌ ์ˆ˜ ์žˆ๋Š” terminal ์ง‘ํ•ฉ A->X1X2X3์ผ๋•Œ, LOOKAHEAD(A) = FIRST(X1) โŠ• FIRST(X2) … โŠ• FOLLOW(A) Strong LL(1) LL(1)๊ณผ ํ•ญ์ƒ ๋™์ผ (1์ด ์•„๋‹๋•Œ๋Š” ๋‹ค๋ฆ„) LOOKAHEAD(A->ฮฑ)์™€ LOOKAHEAD(A->ฮฒ)๊ฐ€ ๊ฒน์น˜์ง€ ์•Š๋Š” ๋ฌธ๋ฒ• LL(1) ํŒŒ์„œ ๊ตฌํ˜„ ๋ฐฉ๋ฒ• Recursive descent parser ์žฅ์  : ์ง๊ด€์  ์‰ฝ๋‹ค ๋‹จ์  : ์ƒ์„ฑ ๊ทœ์น™์ด ๋ฐ”๋€Œ๋ฉด ๊ตฌ๋ฌธ ๋ถ„์„๊ธฐ๋ฅผ ๊ณ ์ณ์•ผ ํ•œ๋‹ค Predictive parser PDA(PushDown Automata)์— ๊ธฐ๋ฐ˜ ์ƒ์„ฑ ๊ทœ์น™์ด ๋ฐ”๋€Œ๋ฉด ํŒŒ์‹ฑ ํ…Œ์ด๋ธ”๋งŒ ์ˆ˜์ • ํŒŒ์‹ฑํ…Œ์ด๋ธ” ์˜ˆ์‹œ (?์—๋Š” ๊ทœ์น™๋ฒˆํ˜ธ๊ฐ€ ๋“ค์–ด๊ฐ„๋‹ค) a b S ? ? A ? ? ํŒŒ์‹ฑํ…Œ์ด๋ธ”์— ๋‘๊ฐœ ์ด์ƒ์˜ ์ƒ์„ฑ ๊ทœ์น™์ด ๋“ค์–ด๊ฐ€๋Š” ๊ฒฝ์šฐ -> NOT LL(1) Stack์˜ ์˜ˆ์‹œ Bottom-up parsing left-recursive ๋ฌธ๋ฒ•๋„ ํŒŒ์‹ฑ ๊ฐ€๋Šฅ LL(k) ์ขŒ์ธก์œ ๋„ ๊ธฐ๋ฐ˜ k๊ฐœ์˜ symbol์„ lookahead Top-down parsing, recursive descent parsing, predictive parsing, LL parser ํŒŒ์ŠคํŠธ๋ฆฌ๋ฅผ pre-roder๋กœ ์ˆœํšŒ ๋ฐ ์ƒ์„ฑ LR(k) ์šฐ์ธก์œ ๋„ ๊ธฐ๋ฐ˜ k๊ฐœ์˜ symbol์„ lookahead Bottom-up parsing, shift-reduce parsing, LR parser ํŒŒ์ŠคํŠธ๋ฆฌ๋ฅผ post-order๋กœ ์ˆœํšŒ ๋ฐ ์ƒ์„ฑ Reduce S=>ฮฑฮฒฯ‰์ด๊ณ  A->ฮฒ์ด๋ฉด ฮฒ๋ฅผ A๋กœ ๋Œ€์น˜ํ•˜๋Š” ๊ฒƒ : S=>ฮฑAฯ‰ ์‹œ์ž‘ symbol์ด ๋‚˜์˜ฌ ๋•Œ๊นŒ์ง€ reduce ํ•œ๋‹ค Handle S=>ฮฑฮฒฯ‰์ด๊ณ  A->ฮฒ์ด๋ฉด ฮฒ๋ฅผ ฮฑฮฒฯ‰์˜ handle์ด๋ผ๊ณ  ํ•œ๋‹ค ๋‘ ๊ฐœ ์ด์ƒ์˜ handle์ด ์กด์žฌํ• ๋•Œ -> ๋ชจํ˜ธํ•˜๋‹ค Shift์™€ Reduce๋กœ Parsing ํ•˜๊ธฐ Stack์˜ ์˜ˆ์‹œ Issue Shift์™€ Reduce ์ค‘ ์–ด๋А ๊ฒƒ์„ ํ• ๊นŒ? Stack์˜ top์—์„œ ์–ผ๋งˆ๋งŒํผ์„ handle๋กœ ๋ณผ ๊ฒƒ์ธ๊ฐ€? ํ•ด๊ฒฐ๋ฐฉ๋ฒ•: LR Parsing Table YACC LALR ํŒŒ์„œ ์ƒ์„ฑ๊ธฐ foo.y –(yacc)–> y.tab.c –(gcc)–> a.out *.y ํŒŒ์ผ ๊ตฌ์กฐ 1<์„ ์–ธ๋ถ€> 2... 3%% 4... 5exp : exp '+' term; 6factor : ident; 7... 8%% 9<์—ฌ๋Ÿฌ ํ•จ์ˆ˜> ๋ชจํ˜ธํ•œ ๋ฌธ๋ฒ•์œผ๋กœ LR Conflict ๋ฐœ์ƒ ์‹œ ์„ ์–ธ๋ถ€์—์„œ ์šฐ์„ ์ˆœ์œ„ ์ง€์ •ํ•˜์—ฌ ํ•ด๊ฒฐ LR Parsing Table Action table : Action + Parser ์ƒํƒœ Goto table : Parser ์ƒํƒœ LR(0) ํŒŒ์‹ฑ ํ…Œ์ด๋ธ” ๋งŒ๋“ค๊ธฐ LR(0) ์•„์ดํ…œ rhs์— ์ (’.’) symbol์„ ๊ฐ€์ง„ ์ƒ์„ฑ ๊ทœ์น™ ex) A->ฮฑ.ฮฒ, A->. closure ์ (’.’)๋’ค์— non-terminal์ด ์˜ค๋ฉด ์žฌ๊ท€์ ์œผ๋กœ ์ถ”๊ฐ€ S’ -> S, S -> (L)|id, L -> S | L,S closure({[S’->.S]}) = {[S’->.S], [S->.(L)], [S->.id]} goto goto(I, X)์ด๋ฉด ์ ์„ X๋’ค๋กœ ์˜ฎ๊ธฐ๊ณ  closure๋ฅผ ์ทจํ•œ๋‹ค X๊ฐ€ ์—†์œผ๋ฉด ๋„ฃ์ง€ ์•Š๋Š”๋‹ค I={[G->E=E], [E->E.+T]} ์ผ๋•Œ, goto(I, +) = closure({E->E+.T}) : ์ ์„ +๋’ค๋กœ ์˜ฎ๊น€ C0 ์ƒ์„ฑ๊ทœ์น™ S’->S์—์„œ๋ถ€ํ„ฐ ์ฐจ๋ก€๋กœ closure์™€ goto๋ฅผ ์ ์šฉํ•˜์—ฌ ์–ป์€ ๋ชจ๋“  ํƒ€๋‹นํ•œ LR(0)์˜ ์•„์ดํ…œ ์ง‘ํ•ฉ๋“ค Item์˜ ์ข…๋ฅ˜ [A->X.Y] : X!=ฮต์ผ๋•Œ kernel item [A->.X] : closure item [A->X.] : reduce item SLR ํŒŒ์‹ฑ ํ…Œ์ด๋ธ” ๋งŒ๋“ค๊ธฐ reduce Item์ด [X->ฮฑ.]์ผ๋•Œ, FOLLOW(X)์˜ ๋ชจ๋“  terminal์—๋งŒ reduce action์„ ๋„ฃ๋Š”๋‹ค ๋‚˜๋จธ์ง€๋Š” LR(0)๊ณผ ๋˜‘๊ฐ™๋‹ค LR(0)๋ณด๋‹ค conflict๊ฐ€ ์ ์–ด, ๋” ์ •๊ตํ•˜๋‹ค๊ณ  ํ•  ์ˆ˜ ์žˆ๋‹ค. LALR Parsing ์ •๊ตํ•œ ์ˆœ์„œ LR(0) < SLR < LALR(1) < LR(1) ํŒŒ์„œ ์ƒํƒœ์˜ ๊ฐœ์ˆ˜ SLR = LALR « LR(1) SDD, AST SDD (Syntax Directed Definition) SDD : semnatic action์„ ์ •์˜ํ•˜๋Š” ์ถ”์ƒ์ ์ธ ๋ช…์„ธ์„œ Semnatic Actions : ๊ทœ์น™์— ๋Œ€ํ•œ Action Yacc/Bison : $$, $1, $2, ... ์‚ฌ์šฉ ANTLR : $<name> ์‚ฌ์šฉ Type declaration Attribute ์ข…๋ฅ˜ synthesized attr. : children์— ์˜ํ•ด ๊ณ„์‚ฐ (terminal) inherited attr. : parent, sibling์— ์˜ํ•ด ๊ณ„์‚ฐ AST (Abstract Syntax Tree) ํŒŒ์ŠคํŠธ๋ฆฌ์—์„œ ๋ถˆํ•„์š”ํ•œ ์ •๋ณด๋ฅผ ์ œ๊ฑฐํ•œ ํ˜•ํƒœ AST๋ฅผ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• ํŒŒ์‹ฑ๋‹จ๊ณ„์—์„œ ๋งŒ๋“ค๊ธฐ : LL, LR ํŒŒ์ŠคํŠธ๋ฆฌ๋ฅผ ์ˆœํšŒํ•˜๋ฉด์„œ ๋งŒ๋“ค๊ธฐ : SDD ์‚ฌ์šฉ (Yacc etc.) evaluation : ๋…ธ๋“œ๋ฅผ ๋ฐฉ๋ฌธํ•˜๋ฉด์„œ ์ž‘์—…ํ•˜๋Š” ํ–‰์œ„ On-the-fly evaluation S-attributed SDD: synthesized attribute๋งŒ ๊ฐ€์ง€๊ณ  ์žˆ๋Š” SDD L-attributed SDD: synthesized attribute๋งŒ ๊ฐ€์ง€๋Š” ๊ฒฝ์šฐ + ๊ฐ’์ด ์™ผ์ชฝ์—์„œ ์˜ค๋ฅธ์ชฝ์œผ๋กœ ํ˜๋Ÿฌ ๊ณ„์‚ฐ์ด ์ด๋ฃจ์–ด์ง€๋Š” ๊ฒฝ์šฐ IR (Intermediate Representation) IR์ด๋ž€? Tree๋‚˜ Instruction list ํ˜•ํƒœ instruction(node)๊ฐ€ ์ ์–ด์•ผ ์ตœ์ ํ™”/๋ฒˆ์—ญ์— ์ข‹์Œ High Level IR High์™€ Low๋Š” ์ƒ๋Œ€์ ์ธ ๊ฐœ๋… High level IR: ์—ฌ๊ธฐ์„œ๋Š” AST์˜ ๋ณ€ํ˜•๋งŒ ์ƒ๊ฐ ์ข…๋ฅ˜ : AST, TCOL Low Level IR ๋‹จ์ˆœํ•œ instruction์œผ๋กœ ๊ตฌ์„ฑ ๊ฐ€์ƒ๊ธฐ๊ณ„(์ฃผ๋กœ RISC)๋ฅผ emulate N-tuple ํ‘œ๊ธฐ๋ฒ• (3-address code) a = b OP c ์ผ๋ฐ˜์ ์œผ๋กœ ๊ธฐ๊ณ„์–ด๊ฐ€ ๊ฐ€์ง€๋Š” ํ”ผ์—ฐ์‚ฐ์ž ๊ฐœ์ˆ˜ <= 3 quadruple : (์—ฐ์‚ฐ์ž, ํ”ผ์—ฐ์‚ฐ์ž1, ํ”ผ์—ฐ์‚ฐ์ž2, ๊ฒฐ๊ณผ) Stack machine code Java byte code, U-code : AST๋กœ๋ถ€ํ„ฐ ์ƒ์„ฑ์ด ์šฉ์ด Tree ํ‘œํ˜„ ๊ธฐ๊ณ„์–ด ์ƒ์„ฑ ์šฉ์ด IR ์˜ˆ์‹œ GCC - GIMPLE (3-address code) GCC์˜ ์ค‘๊ฐ„์ฝ”๋“œ : GENERIC -> GIMPLE -> RTL 1D.1954 = x*10 // D.1954๋Š” ์ž„์‹œ๋ณ€์ˆ˜ 2gimple_assign <mult_exprt, D.1954, x, 10> LLVM - bit (3-address code) LLVM IR : ์–ธ์–ด์™€ ๋จธ์‹ ์— ๋…๋ฆฝ์  1@var = global i32 14 ; ์ „์—ญ๋ณ€์ˆ˜ var์— 14 ๋Œ€์ž… 2define i32 @main() nounwind { ; i32(int) ๋ฐ˜ํ™˜ํ˜• 3 entry: 4 %a = alloca i32, align 4 ; ์ง€์—ญ๋ณ€์ˆ˜ a ์„ ์–ธ, int ํ• ๋‹น 5 %1 = load i32 * @var ; %1 ์ž„์‹œ๋ณ€์ˆ˜์— var๊ฐ’ ๋Œ€์ž… 6 ret i32 %1 ; ์ž„์‹œ๋ณ€์ˆ˜ ๊ฐ’ ๋ฐ˜ํ™˜ 7} JVM - byte code (stack machine code) ๊ฐ€์ƒ ๊ธฐ๊ณ„ ์ฝ”๋“œ (Bytecode, MSIL) ๊ฐ€์ƒ ๊ธฐ๊ณ„์—์„œ ๋™์ž‘ํ•˜๋„๋ก ํ•จ ์ด์‹์„ฑ, ํ˜ธํ™˜์„ฑ์ด ๋ชฉ์  : java bytecode๋Š” machine ํ˜ธํ™˜์„ฑ, c# msil์€ language ํ˜ธํ™˜์„ฑ 1public Employee(String strName, int num) 2{name = strName; idNumber = num; storeData(strName, num);} 3Method Employee(java.lang.String, int) 4 50 aload_0 ; 0๋ฒˆ์งธ ๋กœ์ปฌ๋ณ€์ˆ˜(this)๋ฅผ ์Šคํƒ์— push 61 invokespecial #3 <Method java.lang.Object()> ; ํ•จ์ˆ˜ ํ˜ธ์ถœ 7--- 84 aload_0 95 aload_1 ; strName์„ ์Šคํƒ์— push 106 putfield #5 <Field java.lang.String name> ; name์— strName ๋Œ€์ž… 11--- 129 aload_0 1310 iload_2 ; num์„ ์Šคํƒ์— push 1411 putfield #7 <Field int idNumber> ; idNumber์— num ๋Œ€์ž… 15--- 1614 aload_0 1715 aload_1 ; strName์„ ์Šคํƒ์— push 1816 iload_2 ; num์„ ์Šคํƒ์— push 1917 invokespecial #9 <Method void storeData(java.lang.String, int)> ; ํ•จ์ˆ˜ ํ˜ธ์ถœ 2020 return line number : ๋ช…๋ น์ด ์‹œ์ž‘ํ•˜๋Š” ๋ฐ”์ดํŠธ ์ฃผ์†Œ aload : ๊ฐ์ฒด๋ฅผ push, iload : ์ •์ˆ˜๋ฅผ push ์›๋ž˜๋Š” aload๊ฐ€ ๋ช…๋ น, ์ž์ฃผ ์“ฐ๋Š” ๋ช…๋ น aload 0์„ ๋ฌถ์–ด์„œ bind -> aload_0 CIL (Common Intermediate Language) (stack machine code) C#, VB.NET, J# ๋“ฑ์—์„œ ์‚ฌ์šฉ MSIL์€ ์˜›๋‚  ์ด๋ฆ„ 1.assembly Hello {} ; .assembly: ์–ด์…ˆ๋ธ”๋ฆฌ ์„ ์–ธ 2.assembly extern mscorlib {} 3.method static void Main() { 4 .entrypoint 5 .maxstack 1 6 ldstr "Hello, world!" ; stack์— ์ €์žฅ 7 call void [mscorlib]System.Console::WriteLine(string) 8 ret 9} GCC RTL(Register Transfer Language) (Tree๊ตฌ์กฐ ์ฝ”๋“œ) Lisp S-expression ์‚ฌ์šฉ 1(set (reg:SI 140) 2 (plus:SI (reg:SI 138) 3 (reg:SI 139))) => reg140 = reg138+reg139 IR generation 3-address Translation ๊ทœ์น™ Binary operations: t = [[el OP e2]] Unary operations: t = [[OP el]] Array access: t = [[ v[e] ]] Structure access: t = [[ v.f ]] Short-circuit OR: t = [[ el SC-OR e2]] Statement sequence: [[s1; s2; ...; sN]] Variable assignment: [[ v = e ]] Array assignment: [[ v[e1] = e2 ]] If: [[ if(e) then s ]], [[ if(e) then s1 else s2]] While: [[ while (e) s ]] Switch: [[ switch (e) case v1:s1, ..., case vN:sN ]] Function Call: [[ call f(e1, e2, ..., eN) ]] Fucntion Return: [[ return e ]] Statement Expression Statement๋„ expression ์ฒ˜๋Ÿผ ๊ฐ’์„ ๊ฐ€์ง€๋„๋ก ํ™•์žฅ t = [[ S ]]๋ฅผ ์ถ”๊ฐ€ํ•˜์—ฌ ๊ฒฐ๊ณผ๊ฐ’์„ ์ €์žฅํ•˜์ž Nested Expressions t = [[ (a - b) * (c + d) ]] t = [[ if c then if d then a = b ]] ๊ฐ€์žฅ ํฐ ๋ฉ์–ด๋ฆฌ๋ถ€ํ„ฐ ๋ฐ”๊พผ๋‹ค Storage Management 2๊ฐ€์ง€ Storage Register : ๋น ๋ฅธ ์ ‘๊ทผ, ๊ฐ„์ ‘ ์ ‘๊ทผ ๋ถˆ๊ฐ€ Memory : ์ƒ๋Œ€์ ์œผ๋กœ ๋А๋ฆฐ ์ ‘๊ทผ, ๊ฐ„์ ‘ ์ ‘๊ทผ ๊ฐ€๋Šฅ 2๊ฐ€์ง€ ์ ‘๊ทผ ๋ฐฉ์‹ All memory approach ๋ชจ๋“  ๋ณ€์ˆ˜๋ฅผ memory์— ์ €์žฅ, ๊ฐ€๋Šฅํ•œ๊ฒƒ๋งŒ register Standard approach Global, Statics, Local(composite)๋Š” memory์— ์ €์žฅ Local(scalar)๋Š” memory ๋˜๋Š” virtual register์— ์ €์žฅ Memory์˜ 4๋Œ€ ์˜์—ญ Code space : ๋ช…๋ น์–ด๋ฅผ ์ €์žฅ read-only์ผ๋•Œ ๋น ๋ฆ„ Static data : ํ”„๋กœ๊ทธ๋žจ๊ณผ lifetime์„ ํ•จ๊ป˜ํ•˜๋Š” ๋ฐ์ดํ„ฐ Stack : Local ๋ณ€์ˆ˜๋“ค Heap : ๋™์ ์œผ๋กœ ํ• ๋‹น๋˜๋Š” ๋ฐ์ดํ„ฐ File Format Windows : PE (Portable Executable) Unix : ELF (Executable and Linkable Format) ๋ณ€์ˆ˜ ๋ฐ”์ธ๋”ฉ environment : <๋ณ€์ˆ˜, storage location> ์ •๋ณด state: <๋ณ€์ˆ˜, ๊ฐ’> ์ •๋ณด ์–ด๋–ค ๋ณ€์ˆ˜ N์ด storage location S์— ์ง€์ •๋˜๋ฉด ๋ฐ”์ธ๋”ฉ ๋œ๋‹ค๊ณ  ํ•œ๋‹ค Static Allocation ํ”„๋กœ๊ทธ๋žจ ์ˆ˜ํ–‰ํ•˜๋Š” ๋™์•ˆ ๋ณ€ํ•˜์ง€ ์•Š๋Š” location์œผ๋กœ ๋ฐ”์ธ๋”ฉ Heap Allocation ์—ฐ์†์ ์ธ global ์˜์—ญ์˜ ์ผ๋ถ€๋ฅผ OS๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ๊ฒƒ ํ”„๋กœ๊ทธ๋žจ ์ˆ˜ํ–‰ ์ค‘ ์š”์ฒญ๊ณผ ๋ฐ˜ํ™˜ Stack Management Run-time stack : ํ•œ ํ•จ์ˆ˜ call๋งˆ๋‹ค ํ•˜๋‚˜์”ฉ๋‘๋Š” frames Activation record : ํ•จ์ˆ˜ ์ˆ˜ํ–‰์„ ์œ„ํ•œ execution env(local var, parameter, return address, etc.) Top frame : ํ˜„์žฌ ์ˆ˜ํ–‰์ค‘์ธ ํ•จ์ˆ˜์˜ frame Stack pointers SP : Frame top FP : Frame base ๋‘ ๊ฐœ๋ฅผ ์“ฐ๋Š” ์ด์œ  ๊ฐ€๊นŒ์šด ๊ฑฐ ๊ธฐ์ค€์œผ๋กœ offset ๊ณ„์‚ฐ -> small offset ์œ ์ง€ ์ˆ˜ํ–‰ ์ค‘ top frame์˜ ์œ„์น˜๋ฅผ ์•Œ ์ˆ˜ ์—†์Œ Semantic Analysis - Symbol Tables Scope Identifier: ์‹๋ณ„์ž Lexical Scope: ํŠน์ • ๋ฒ”์œ„ ์‹๋ณ„์ž์˜ Scope: ๊ทธ ์‹๋ณ„์ž์˜ ์„ ์–ธ์ด ์ฐธ์กฐ๋˜๋Š” lexical scope Symbol Table Name Kind Type Attribute foo func int, int -> int extern m arg int tmp var char const ํ•˜๋‚˜์˜ lexical๋งˆ๋‹ค ํ•˜๋‚˜์˜ symbol table symbol table์€ ๊ณ„์ธต์ ์ด๋‹ค ํ˜„์žฌ scope์— ์—†์œผ๋ฉด ์ƒ์œ„ scope๋กœ ์˜ฌ๋ผ๊ฐ€๋ฉด์„œ ์ฐพ๋Š”๋‹ค Symbol Table Implementation AST๊ฐ€ ๋งŒ๋“ค์–ด์ ธ์•ผ ๊ฐ€๋Šฅ Local Table์€ hash table ์‚ฌ์šฉ Global Table์€ N-array tree ๊ตฌ์กฐ ์‚ฌ์šฉ ์ฝ”๋“œ๋ฅผ ์ˆœ์ฐจ๋Œ€๋กœ ์ฝ์œผ๋ฉด์„œ ๋งŒ๋“ฌ (scope ์Šคํƒ์„ ์‚ฌ์šฉ) Type Checking Type Expressions Array types: T[], T[10] Structure types : {id1: T1, id2: T2 …} Pointer types: T* Function types: T1 X T2 X … X Tn -> T_return Type Judgement A โ”œ E : T A ์ƒํ™ฉ์—์„œ E๋Š” Tํƒ€์ž…์„ ๋งŒ์กฑํ•œ๋‹ค A โ”œ if(E) S1 else S2 : T ์œ„ ์กฐ๊ฑด์€ ๋ชจ๋“  E, S1, S2, A, T์— ๋Œ€ํ•œ ๊ฐ€์ •์ด ์„ฑ๋ฆฝํ•  ๋•Œ ๊ฒฐ๋ก  T๊ฐ€ ์„ฑ๋ฆฝํ•œ๋‹ค Proof Tree (ํƒ€์ž… ์œ ๋„ ํŠธ๋ฆฌ) ์—ญ์‚ผ๊ฐํ˜• ๋ชจ์–‘ ๋งŒ์กฑํ•˜๋Š” proof tree๊ฐ€ ์žˆ๋‹ค -> ํƒ€์ž… ์˜ค๋ฅ˜๊ฐ€ ์—†๋‹ค ๊ทธ ์™ธ Semantic Analyses break, continue, goto ๋ฌธ์ด ์˜ฌ๋ฐ”๋ฅธ ์œ„์น˜์— ์žˆ๋Š” ์ง€ ๋“ฑ ์ปดํŒŒ์ผ๋Ÿฌ ํ›„๋ฐ˜๋ถ€ (๋น ๋ฅด๊ณ , ์‹ค์ œ ๋Œ์•„๊ฐ€๋Š” ์ฝ”๋“œ๋กœ ๋ฐ”๊พธ๊ธฐ) Instruction Selection Tree ๊ธฐ๋ฐ˜ Intermediate Representation MEM(e) : ์ฃผ์†Œ e๋กœ ์‹œ์ž‘ํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ํ•œ word์˜ ๋‚ด์šฉ TEMP(t) : ๋ ˆ์ง€์Šคํ„ฐ t SEQ(s1, s2): ๋ฌธ์žฅ s1 ์ˆ˜ํ–‰ ํ›„ s2 ์ˆ˜ํ–‰ ESEQ(s, e): ๋ฌธ์žฅ s ์ˆ˜ํ–‰ ํ›„ (๊ฒฐ๊ณผ ์—†์Œ) e๊ฐ€ ์ถ”๊ฐ€ ์ˆ˜ํ–‰ BINOP(o, e1, e2) : ์—ฐ์‚ฐ์ž o, ํ”ผ์—ฐ์‚ฐ์ž e1, e2, ๊ฒฐ๊ณผ ์ €์žฅ๋œ ์ฃผ์†Œ ๋ฐ˜ํ™˜ const(i): ์ •์ˆ˜ ์ƒ์ˆ˜ i Register Allocation ์ตœ์ ํ™” ํ•˜๊ธฐ ์œ„ํ•ด ์ตœ๋Œ€ํ•œ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ๊ฒƒ์„ Register์— ์ €์žฅ Interference ์„œ๋กœ ๋‹ค๋ฅธ ๋‘ definition์ด live range ์—์„œ ๊ณตํ†ต operation์„ ๊ฐ€์ง€๊ณ ์žˆ๋Š” ๊ฒฝ์šฐ Interference Graph : ์„œ๋กœ interfere ํ•˜๋ฉด ์—ฐ๊ฒฐํ•˜๋Š” ๊ทธ๋ž˜ํ”„ Graph coloring : ์—ฐ๊ฒฐ๋œ ๋…ธ๋“œ๋Š” ๋‹ค๋ฅธ ์ƒ‰์œผ๋กœ ์น ํ•˜๊ธฐ Instruction Scheduling instruction์˜ ์ˆœ์„œ๋ฅผ ๋ฐ”๊พธ์–ด stall ๊ฐœ์ˆ˜ ๋“ฑ์„ ์ค„์—ฌ์„œ ์ˆ˜ํ–‰์†๋„๋ฅผ ๋†’์ด๋Š” ๊ฒƒ stall : ๋‹ค๋ฅธ ๋ช…๋ น์–ด ์ˆ˜ํ–‰์„ ๊ธฐ๋‹ค๋ฆฌ๋А๋ผ CPU๋ฅผ ๋‚ญ๋น„ํ•˜๋Š” ๊ฒƒ ๋ชฉํ‘œ Wasting time์„ ์ค„์ธ๋‹ค ๋™์ผํ•œ ์ฝ”๋“œ๊ฐ€ ๋‚˜์™€์•ผํ•œ๋‹ค register spilling์„ ํ”ผํ•ด์•ผํ•œ๋‹ค Static scheduling ๋‹จ๊ณ„ Local basic scheduling, Loop scheduling, global scheduling Local basic scheduling List scheduling : greedy, heuristic, local technique ์‚ฌ์šฉ precedence graph๋ฅผ ๋งŒ๋“ ๋‹ค ๊ฐ ๋…ธ๋“œ์— priority function์„ ์ ์šฉํ•œ๋‹ค “ready-operation queue"๋ฅผ ์—์„œ ready operation์„ ํ•˜๋‚˜ ์„ ํƒ ํ›„ scheduling, ready operation queue๋ฅผ ์—…๋ฐ์ดํŠธํ•œ๋‹ค. Longest latency-weighted path๋ฅผ ์ด์šฉํ•ด์„œ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ •ํ•œ๋‹ค ๊ธฐํƒ€ Optimization ๋ฐฉ๋ฒ• addr r1 1 -> inc r1 ํŠน์ˆ˜ ์„ฑ์งˆ์˜ ๋ ˆ์ง€์Šคํ„ฐ ํ™œ์šฉ ํŠน์ˆ˜ ๋ชฉ์ ์˜ ๋ช…๋ น์–ด ํ™œ์šฉ Register ๊ฐ„ mov ์ œ๊ฑฐ ์ค‘๋ณต๋œ load ์ œ๊ฑฐ Control Flow Optimizations(์ตœ์ ํ™”) ์ฃผ์–ด์ง„ ์ž…๋ ฅ ํ”„๋กœ๊ทธ๋žจ์„ ์ข€ ๋” ํšจ์œจ์ ์ธ ์ฝ”๋“œ๋กœ ๋ฐ”๊พธ๋Š” ๊ฒƒ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋ถ„๋ฅ˜ ๋ฐฉ๋ฒ• ๋ถ„์„ : Control Flow Analysis vs Data Flow Analysis ์ตœ์ ํ™” Inner basic block(local) vs Inter basic block(global) Cyclic code opt vs Acyclic code opt Control Flow Analysis Control Flow ํ”„๋กœ๊ทธ๋žจ์˜ ๊ฐ€๋Šฅํ•œ ์ˆ˜ํ–‰์ˆœ์„œ (๋ถ„๊ธฐ) Branch Execution -> dynamic control flow : ์‹คํ–‰ ํ•ด๋ด์•ผ ํ™•์ธ ๊ฐ€๋Šฅ Compiler -> static control flow : ์ปดํŒŒ์ผ๋Ÿฌ๊ฐ€ ๋ถ„์„ํ•ด์„œ ์•Œ ์ˆ˜ ์žˆ์Œ Analysis ์ •์  ์„ฑ์งˆ (static property): ํ”„๋กœ๊ทธ๋žจ ์ˆ˜ํ–‰ ์—†์ด ๋„์ถœ ๋˜๋Š” ์„ฑ์งˆ CFA(Control Flow Analysis) : ์ฝ”๋“œ์˜ ๋ถ„๊ธฐ ๊ตฌ์กฐ๋ฅผ CFG ํ˜•ํƒœ๋กœ ํ‘œํ˜„ Basic Block ๋™์ผํ•œ execution condition์„ ์ ์šฉ๋ฐ›๋Š” instruction ๋ฌถ์Œ instruction ์™ธ์—๋Š” branch๊ฐ€ ์—†์Œ Maximal basic block ๊ตฌํ•˜๊ธฐ BB์˜ leader(์ฒซ๋ฒˆ์งธ instruction)๋ฅผ ์ฐพ๋Š”๋‹ค ๋‹ค์Œ leader ์ด์ „๊นŒ์ง€์˜ instruction์„ ๊ตฌํ•œ๋‹ค Weighted CFG Profiling: ๋ฐ˜๋ณตํ•ด์„œ ์ˆ˜ํ–‰ํ•ด๋ณด๋ฉด์„œ ์‹คํ–‰ํšŸ์ˆ˜๋ฅผ ์–ป์Œ ์–ป์€ weight๋ฅผ edge์— ํ‘œ์‹œ Control Flow Optimization Acyclic Code Loop๊ฐ€ ์—†๋Š” ์ฝ”๋“œ ๋ถ„์„ ๋ฐ ์ตœ์ ํ™”๊ฐ€ ์ƒ๋Œ€์ ์œผ๋กœ ์‰ฌ์›€ ์ข…๋ฅ˜ Inner basic block opt. = Intra opt. = Local opt. Inter basic block opt. = Global opt. Inner Basic Block Optimization Commn subexpression elimination ๊ณตํ†ต๋œ ๋ถ€๋ถ„์ด ์žˆ์œผ๋ฉด ํ•œ๋ฒˆ๋งŒ ๊ณ„์‚ฐ Algebraic simplification ๋Œ€์ˆ˜๋ฒ•์น™์„ ์ด์šฉํ•˜์—ฌ ์‹์„ ๊ฐ„์†Œํ™” ex) x=1*y; -> x=y; Strength reduction ์—ฐ์‚ฐ์ž์˜ ๋น„์šฉ์ด ์ ์€ ๊ฒƒ์œผ๋กœ ๋ฐ”๊พธ๊ธฐ ex) x=x*2; -> x=x+x; ex) y=a/4; -> y=a>>2; Constant folding / propagation folding: ์ปดํŒŒ์ผ ์‹œ๊ฐ„์— ์ƒ์ˆ˜์‹์„ ์ง์ ‘์‹œ๊ฐ„ propagation : ๊ณ ์ •๋œ ๊ฐ’์„ ๊ฐ€์ง€๋Š” ๋ณ€์ˆ˜๋ฅผ ์ƒ์ˆ˜๋กœ ๋Œ€์ฒด Inter Basic Block Optimization Global application of inner basic block optimization Global common subexpression elimination basic block ๊ฐ„์˜ ๊ณตํ†ต ๋ถ€๋ถ„์‹์— ๋Œ€ํ•ด ํ•œ๋ฒˆ๋งŒ ๊ณ„์‚ฐ Global constant folding / propagation basic block ๊ฐ„์˜ ์ƒ์ˆ˜๋ฅผ ์ธ์‹ํ•˜์—ฌ ํ•œ๋ฒˆ๋งŒ ๊ณ„์‚ฐ Other transformation Branch to unconditional branch ๋ถˆํ•„์š”ํ•œ ๋ถ„๊ธฐ ์ œ๊ฑฐ Unconditional branch to branch ๋ถ„๊ธฐ ํ›„ ๋ฐ”๋กœ ๋ถ„๊ธฐ -> ๋ถ„๊ธฐ ํ•œ๋ฒˆ์œผ๋กœ ๋ณ€๊ฒฝ Branch to next basic block (next instr) ๋ถ„๊ธฐ ํ›„ ๋ฐ”๋กœ ๋‹ค์Œ basic block์œผ๋กœ ๋ถ„๊ธฐ ์ œ๊ฑฐ Basic block merging ๋‘ basic block์„ ํ•ฉ์นจ Branch to same target ๊ฐ™์€ basic block์œผ๋กœ ๋ถ„๊ธฐํ•˜๋Š” ๊ฒƒ์„ ์ œ๊ฑฐ Branch target expansion ๋ถ„๊ธฐ ๋Œ€์ƒ์ด ๋˜๋Š” basic block์„ ํ•ฉ์นจ Unreachable code elimination Entry์—์„œ ๋„๋‹ฌํ•  ์ˆ˜ ์—†๋Š” ‘unreachable’ block ์ œ๊ฑฐ Loop Optimization Loop๋Š” ํ•œ๋ฒˆ optimizeํ•˜๋ฉด ํšจ๊ณผ๊ฐ€ ํฌ๋‹ค Loop unrolling : ๋ฐ˜๋ณต๋ฌธ์„ ํ’€์–ด์„œ ๋ฐ˜๋ณต ํšŸ์ˆ˜๋ฅผ ์ค„์ž„ Loop invarient : ๋งค๋ฒˆ ๋™์ผํ•œ ๊ฐ’์„ ๋‚ด๋Š” ๋ฌธ์žฅ์„ ๋ฐ˜๋ณต๋ฌธ ๋ฐ–์œผ๋กœ ๋นผ๋ƒ„ Count up to zero : i๋ฅผ ๊ฐ์†Œํ•˜๋Š” ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ๋ณ€๊ฒฝ (i๋ฅผ 0๊ณผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ์ด n๊ณผ ๋น„๊ตํ•˜๋Š” ๊ฒƒ๋ณด๋‹ค ๋น ๋ฆ„) Dataflow Analysis + Optimization Dataflow Analysis ํ”„๋กœ๊ทธ๋žจ ๋‚ด์— ๊ฐ data ๊ฐ’๋“ค์ด ์ƒ์„ฑ/์†Œ๋ฉธ๋˜๋Š” ์ •๋ณด๋ฅผ ๋ชจ์œผ๋Š” ๊ฒƒ Reaching Definition Analysis definition : ํ•ด๋‹น ๋ณ€์ˆ˜๊ฐ€ assign๋˜๋Š” ๊ฒƒ reach : definition d๊ฐ€ ํŠน์ • ์œ„์น˜ p์— ๋„๋‹ฌํ•œ๋‹ค kill : definition d์˜ ๋‘๊ฐœ์˜ ํฌ์ธํŠธ์‚ฌ์ด์—์„œ ๋‹ค๋ฅธ definition์ด ์กด์žฌํ•œ๋‹ค GEN/KILL GEN: ๋ธ”๋ก ๋‚ด์—์„œ ์ƒ์„ฑ๋œ definition KILL: ๋ธ”๋ก ๋‚ด์—์„œ ์†Œ๋ฉธ๋œ definition IN/OUT IN : ์ด์ „ ๋ธ”๋ก์˜ OUT์˜ ํ•ฉ์ง‘ํ•ฉ OUT : IN์—์„œ GEN์„ ๋”ํ•˜๊ณ  KILL์„ ๋บ€ ๊ฒƒ
new Nginx์—์„œ HTTPS ์„ค์ •ํ•˜๊ธฐ
๐Ÿ”จ ๊ฐœ๋ฐœ ๋„๊ตฌ
๋ฐฐ๊ฒฝ ํ…Œ์ปค ๋ถ€ํŠธ์บ ํ”„๋ฅผ ์ง„ํ–‰์ค‘์ด๋‹ค. ๋ชจ๋“  ํ”„๋กœ๊ทธ๋žจ์€ docker-compose๋กœ ๊ตฌ์„ฑ๋˜์–ด ์žˆ๋‹ค. AWS EC2์— ๊ตฌ๋™ ์ค‘์ธ ์„œ๋ฒ„์— HTTPS๋ฅผ ์ ์šฉํ•˜๋ ค๊ณ  ํ•œ๋‹ค. ๋„๋ฉ”์ธ ๊ตฌ๋งค ์—†์ด ์‹œ๋„๋ฅผ ํ–ˆ์œผ๋‚˜, AWS์—์„œ ์ œ๊ณตํ•˜๋Š” ๋„๋ฉ”์ธ์œผ๋กœ SSL ์ธ์ฆ์„œ๋ฅผ ๋ฐœ๊ธ‰๋ฐ›์„ ์ˆ˜ ์—†์—ˆ๋‹ค. ๋”ฐ๋ผ์„œ, ๋„๋ฉ”์ธ์„ ๊ตฌ๋งคํ•˜๊ณ , Route 53์„ ํ†ตํ•ด ๋„๋ฉ”์ธ์„ ์—ฐ๊ฒฐํ–ˆ๋‹ค. ๋ชฉํ‘œ Nginx๋ฅผ ์ด์šฉํ•˜์—ฌ HTTPS๋ฅผ ์ ์šฉํ•œ๋‹ค. ๋ฐฉ๋ฒ• 1. docker-compose.yml์— certbot ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์ถ”๊ฐ€ํ•œ๋‹ค. 1certbot: 2 image: certbot/certbot 3 container_name: certbot 4 volumes: 5 - ./certbot/conf:/etc/letsencrypt 6 - ./certbot/www:/var/www/certbot 7 depends_on: 8 - nginx 9 10 # certbot์„ ๋ฌดํ•œ๋ฃจํ”„๋กœ ๋Œ๋ฆฌ๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ 11 entrypoint: "/bin/sh -c 'trap exit TERM; while :; do sleep 6h & wait $${!}; done;'" 2. nginx.conf๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค. # certbot์„ ์‚ฌ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์„ค์ • location /.well-known/acme-challenge/ { allow all; root /var/www/certbot; } 3. certbot ์ปจํ…Œ์ด๋„ˆ๋ฅผ ํ™œ์šฉํ•ด์„œ SSL ์ธ์ฆ์„œ๋ฅผ ๋ฐœ๊ธ‰๋ฐ›๋Š”๋‹ค. 1docker exec -it certbot certbot certonly \ 2 # ์›น ๋ฃจํŠธ ๋ฐฉ์‹์œผ๋กœ ์ธ์ฆ์„œ๋ฅผ ์ƒ์„ฑ 3 --webroot \ 4 # ์›น ์„œ๋ฒ„์˜ ์›น ๋ฃจํŠธ ๋””๋ ‰ํ„ฐ๋ฆฌ ๊ฒฝ๋กœ๋ฅผ ์ง€์ • 5 --webroot-path=/var/www/certbot \ 6 # ์ธ์ฆ์„œ ๊ฐฑ์‹  ๋ฐ ์ค‘์š”ํ•œ ์•Œ๋ฆผ์„ ๋ฐ›์„ ์ด๋ฉ”์ผ ์ฃผ์†Œ๋ฅผ ์ง€์ • 7 --email {์ด๋ฉ”์ผ ์ฃผ์†Œ} \ 8 # Let's Encrypt ์„œ๋น„์Šค ์•ฝ๊ด€์— ๋™์˜ 9 --agree-tos \ 10 # EFF(Electronic Frontier Foundation) ๋‰ด์Šค๋ ˆํ„ฐ๋ฅผ ๋ฐ›์ง€ ์•Š๋„๋ก ์„ค์ • 11 --no-eff-email \ 12 # SSL ์ธ์ฆ์„œ๋ฅผ ์ƒ์„ฑํ•  ๋„๋ฉ”์ธ ์ด๋ฆ„์„ ์ง€์ • 13 -d {๋„๋ฉ”์ธ ์ด๋ฆ„} 4. Nginx ์›น ์„œ๋ฒ„์™€ ํ•จ๊ป˜ ์‚ฌ์šฉํ•  SSL ์„ค์ • ํŒŒ์ผ์„ ๋‹ค์šด๋กœ๋“œ ๋‹ค์šด ๋ฐ›์€ ํ›„ ํŒŒ์ผ์„ ์•Œ๋งž์€ ์œ„์น˜๋กœ ์ด๋™์‹œํ‚จ๋‹ค. ํ•ด๋‹น ํ”„๋กœ์ ํŠธ์—์„œ๋Š” /etc/letsencrypt/๋กœ ์ด๋™์‹œ์ผฐ๋‹ค. 1sudo curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot-nginx/certbot_nginx/_internal/tls_configs/options-ssl-nginx.conf > "./options-ssl-nginx.conf" 2 3sudo curl -s https://raw.githubusercontent.com/certbot/certbot/master/certbot/certbot/ssl-dhparams.pem > "./ssl-dhparams.pem" 5. nginx.conf๋ฅผ ์ˆ˜์ •ํ•œ๋‹ค. ํ•„์š”ํ•œ ๋ถ€๋ถ„๋งŒ ์ถ”๊ฐ€ํ•˜์˜€๋‹ค. server { listen 80; charset utf-8; server_name {๋„๋ฉ”์ธ ์ด๋ฆ„}; # HTTP ์š”์ฒญ์„ HTTPS๋กœ ๋ฆฌ๋‹ค์ด๋ ‰ํŠธ location / { return 301 https://$host$request_uri; } } server { listen 443 ssl; charset utf-8; server_name { ๋„๋ฉ”์ธ ์ด๋ฆ„ }; # SSL ์ธ์ฆ์„œ ์„ค์ • ssl_certificate /etc/letsencrypt/live/api.forest-of-thoughts.site/fullchain.pem; # SSL ์ธ์ฆ์„œ ํ‚ค ์„ค์ • ssl_certificate_key /etc/letsencrypt/live/api.forest-of-thoughts.site/privkey.pem; # SSL ์„ค์ • ํŒŒ์ผ ํฌํ•จ include /etc/letsencrypt/options-ssl-nginx.conf; # Diffie-Hellman ํ‚ค ์„ค์ • ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; } 6. nginx ์ปจํ…Œ์ด๋„ˆ ์„ค์ •์„ ์ˆ˜์ •ํ•œ๋‹ค. 1nginx: 2 image: nginx:stable 3 ports: 4 - "80:80" 5 - "443:443" 6 volumes: 7 - ./nginx.conf:/etc/nginx/nginx.conf 8 - ./certbot/conf:/etc/letsencrypt 9 - ./certbot/www:/var/www/certbot ํ•ด ํšŒ๊ณ  ๋ณดํ†ต crontab์„ ํ™œ์šฉํ•ด์„œ ์ž๋™์œผ๋กœ ์ธ์ฆ์„œ ๊ฐฑ์‹ ์„ ๋ฐ›๋Š”๋‹ค. ์ด๋ฒˆ์—๋Š” ํ”„๋กœ์ ํŠธ ๊ธฐ๊ฐ„์ด ๊ธธ์ง€ ์•Š์•„์„œ, ์ˆ˜๋™์œผ๋กœ ์ง„ํ–‰ํ–ˆ๋‹ค. ๋‹ค์Œ์—๋Š” ์ž๋™์œผ๋กœ ์ธ์ฆ์„œ ๊ฐฑ์‹ ์„ ๋ฐ›๋Š” ๊ฒƒ๋„ ๋„์ „ํ•ด๋ณด์ž.
new Fastapi - ํ†ตํ•ฉํ…Œ์ŠคํŠธ In-Memory DB์—์„œ ํ…Œ์ด๋ธ”์ด ์—†๋‹ค๋Š” ๋ฌธ์ œ
๐Ÿ Python
์ƒํ™ฉ ํ…Œ์ปค ๋ถ€ํŠธ์บ ํ”„์—์„œ ํŒ€ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ ์ค‘์ด๋‹ค. ๋‹จ์œ„ํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋Š” ์ž‘์„ฑ์ด ์™„๋ฃŒ๋˜์—ˆ๊ณ , ํ†ตํ•ฉํ…Œ์ŠคํŠธ ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑ ์ค‘์ด๋‹ค. sqlite in-memory db๋ฅผ ์‚ฌ์šฉํ•ด์„œ ํ…Œ์ŠคํŠธ ์ค‘์ธ๋ฐ, ํ…Œ์ด๋ธ”์ด ์—†๋‹ค๋Š” ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ–ˆ๋‹ค. ํ…Œ์ŠคํŠธ ์ „์— ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ๊ฐ€ ์‹คํ–‰๋จ์—๋„ ๋ถˆ๊ตฌํ•˜๊ณ , ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค. ์ธ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ์•„๋‹Œ ํŒŒ์ผ๋กœ ์ €์žฅํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์‚ฌ์šฉํ•˜๋ฉด ์—๋Ÿฌ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ๋ณด๊ณ  ๋ฌธ์ œ์˜ ์›์ธ์„ ํŒŒ์•…ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ์ฝ”๋“œ 1from database import Base, engine 2from fastapi.testclient import TestClient 3 4from main import app 5from models import * 6 7# ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ•˜๋Š” ์ฝ”๋“œ์ด๋‹ค 8Base.metadata.create_all(bind=engine) 9 10client = TestClient(app) 11 12 13class TestUserApi: 14 15 def test_create_user(self): 16 test_nickname = "test_nickname" 17 # ์•„๋ž˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๋Š” ์ฝ”๋“œ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค 18 response = client.post( 19 "/api/users", 20 json={"nickname": test_nickname}, 21 ) 22 assert response.status_code == 200 23 assert response.json()["nickname"] == test_nickname ์›์ธ ํ…Œ์ด๋ธ”์„ ์ƒ์„ฑํ• ๋•Œ ๋งŒ๋“ค์–ด์ง€๋Š” ์„ธ์…˜๊ณผ TestClient๊ฐ€ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ๋•Œ ์‚ฌ์šฉํ•˜๋Š” ์„ธ์…˜์ด ๋‹ค๋ฅด๋‹ค. ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• TestClient๋‚ด์— get_db() ํ•จ์ˆ˜๋ฅผ ์ž„์˜๋กœ ์ฃผ์ž…ํ•œ๋‹ค ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค๋ฅผ ์—ฐ๊ฒฐํ• ๋•Œ, ๋‹จ์ผ ์„ธ์…˜์„ ์‚ฌ์šฉํ•˜๋„๋ก ํ•œ๋‹ค. 1from database import Base, engine, get_db 2from sqlalchemy.orm import sessionmaker 3from fastapi.testclient import TestClient 4 5from main import app 6from models import * 7 8Base.metadata.create_all(bind=engine) 9 10client = TestClient(app) 11 12# ํ…Œ์ŠคํŠธ์—์„œ ์‚ฌ์šฉํ•  ์„ธ์…˜์„ ์ƒ์„ฑํ•œ๋‹ค 13TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) 14 15 16Base.metadata.create_all(bind=engine) 17 18# get_db() ํ•จ์ˆ˜๋ฅผ ์žฌ์ •์˜ํ•œ๋‹ค 19def override_get_db(): 20 try: 21 db = TestingSessionLocal() 22 yield db 23 finally: 24 db.close() 25 26# get_db() ํ•จ์ˆ˜๋ฅผ ์žฌ์ •์˜ํ•œ ํ•จ์ˆ˜๋ฅผ ์ฃผ์ž…ํ•œ๋‹ค 27app.dependency_overrides[get_db] = override_get_db 28 29 30class TestUserApi: 31 32 def test_create_user(self): 33 test_nickname = "test_nickname" 34 response = client.post( 35 "/api/users", 36 json={"nickname": test_nickname}, 37 ) 38 assert response.status_code == 201 39 assert response.json()["nickname"] == test_nickname 1engine = create_engine( 2 os.getenv("DATABASE_URL"), 3 # sqlite๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ, ์—ฌ๋Ÿฌ ์Šค๋ ˆ๋“œ์—์„œ ์—ฐ๊ฒฐ์ด ๊ฐ€๋Šฅํ•˜๋„๋ก ์„ค์ •ํ•œ๋‹ค 4 connect_args={"check_same_thread": False}, 5 # ๋‹จ์ผ ์„ธ์…˜์„ ์‚ฌ์šฉํ•˜๋„๋ก ์„ค์ •ํ•œ๋‹ค 6 poolclass=StaticPool, 7)
new ๋ฐฑ์ค€ - 10844 : ์‰ฌ์šด ๊ณ„๋‹จ ์ˆ˜ (S1)
๐Ÿง  Algorithm
์ ‘๊ทผ์ด ์–ด๋ ค์›Œ ์ธํ„ฐ๋„ท์„ ์ฐธ๊ณ ํ–ˆ๋‹ค. ์ฝ”๋“œ๋Š” ๋ณด์ง€ ์•Š์•˜๋‹ค. ์ˆ˜์˜ ๊ธธ์ด๊ฐ€ i์ด๋ฉด์„œ ๋งˆ์ง€๋ง‰ ์ˆซ์ž๊ฐ€ j์ธ ๊ณ„๋‹จ ์ˆ˜์˜ ๊ฐœ์ˆ˜๋ฅผ ์ €์žฅํ•˜๋Š” ๊ฒƒ์ด ํ•ต์‹ฌ์ด๋‹ค. ์ ํ™”์‹์€ L[i][j] = L[i-1][j-1]+L[i-1][j+1] ์ด๋‹ค. 1N = int(input()) 2L = [[0]*12 for _ in range(100)] 3L[0] = [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0] 4 5for i in range(1, N): 6 for j in range(1, 11): 7 L[i][j] = L[i-1][j-1]+L[i-1][j+1] 8 9print (sum(L[N-1])%1000000000)
new ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค - ์—ฐ์† ์ˆ˜์—ด ํ•ฉ์˜ ๊ฐœ์ˆ˜ (L2)
๐Ÿง  Algorithm
์ฒซ๋ฒˆ์งธ ํ’€์ด 1def solution(elements): 2 result = set() 3 length = len(elements) 4 elements = elements*2 5 for i in range(length): 6 temp = 0 7 for j in range(length): 8 temp += elements[i+j] 9 result.add(temp) 10 11 return len(result) ๊ฐœ์„ ํ•œ ํ’€์ด 1def solution(elements): 2result = set() 3length = len(elements) 4for i in range(length): 5 temp = 0 6 for j in range(length): 7 temp += elements[(i+j)%length] 8 result.add(temp) 9 10return len(result) ๋ฌธ์ œ ์ฃผ์–ด์ง„ ์ •์ˆ˜ ๋ฐฐ์—ด๋กœ ์›ํ˜• ์ˆ˜์—ด์„ ๋งŒ๋“ ๋‹ค ์›ํ˜• ์ˆ˜์—ด์˜ ์—ฐ์†๋œ ๋ถ€๋ถ„ ์ˆ˜์—ด์˜ ํ•ฉ์˜ ๊ฐœ์ˆ˜๋ฅผ ๊ตฌํ•˜์—ฌ๋ผ TC input [7,9,1,1,4] ouput 18 ํ•ด๊ฒฐ๋ฐฉ๋ฒ• ์ฒซ๋ฒˆ์งธ ํ’€์ด์—์„œ๋Š” ๋ฐฐ์—ด์„ 2๋ฐฐ๋กœ ๋Š˜๋ ค์„œ ์›ํ˜• ์ˆ˜์—ด์„ ๋งŒ๋“ค์—ˆ๋‹ค ๊ฐœ์„ ํ•œ ํ’€์ด์—์„œ๋Š” mod ์—ฐ์‚ฐ์„ ์ด์šฉํ•ด์„œ ์›ํ˜• ์ˆ˜์—ด์„ ๋งŒ๋“ค์—ˆ๋‹ค set๋ฅผ ์ด์šฉํ•ด์„œ ์ค‘๋ณต์„ ์ œ๊ฑฐํ•˜๊ณ  ์›์†Œ ๊ฐœ์ˆ˜๋ฅผ ๋ฐ˜ํ™˜ํ•˜์˜€๋‹ค
new ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค - ์ด๋ชจํ‹ฐ์ฝ˜ ํ• ์ธํ–‰์‚ฌ (L2)
๐Ÿง  Algorithm
1result = [] 2 3def dfs(size, percent, users, emoticons): 4 global result 5 6 if len(percent) == size: 7 temp = [0] * len(users) 8 for i in range(size): 9 for j in range(len(users)): 10 if percent[i]*100 >= users[j][0]: 11 temp[j] += emoticons[i]*(1-percent[i]) 12 serviceNum = 0 13 income = 0 14 for i in range(len(users)): 15 if temp[i] >= users[i][1]: 16 serviceNum += 1 17 else: 18 income += temp[i] 19 result.append ((serviceNum, income)) 20 return 21 22 for i in [0.1, 0.2, 0.3, 0.4]: 23 dfs(size, percent+[i], users, emoticons) 24 25 26def solution(users, emoticons): 27 dfs(len(emoticons), [], users, emoticons) 28 result.sort(reverse=True) 29 return list(result[0]) ๋ฌธ์ œ ์นด์นด์˜คํ†ก ์‚ฌ์šฉ์ž n๋ช…์˜ ๊ตฌ๋งค ๊ธฐ์ค€์„ ๋‹ด์€ 2์ฐจ์› ์ •์ˆ˜ ๋ฐฐ์—ด users, ์ด๋ชจํ‹ฐ์ฝ˜ m๊ฐœ์˜ ์ •๊ฐ€๋ฅผ ๋‹ด์€ 1์ฐจ์› ์ •์ˆ˜ ๋ฐฐ์—ด emoticons๊ฐ€ ์ฃผ์–ด์ง„๋‹ค ๊ฐ ์‚ฌ์šฉ์ž๋Š” ์ผ์ • ๋น„์œจ ์ด์ƒ ํ• ์ธํ•˜๋Š” ์ด๋ชจํ‹ฐ์ฝ˜์„ ๊ตฌ๋งคํ•œ๋‹ค ๊ฐ ์‚ฌ์šฉ์ž๋Š” ๊ตฌ๋งคํ•œ ์ด๋ชจํ‹ฐ์ฝ˜ ๊ฐ€๊ฒฉ์˜ ํ•ฉ์ด ์ผ์ • ๊ธฐ์ค€์„ ๋„˜์œผ๋ฉด ์ด๋ชจํ‹ฐ์ฝ˜ ๊ตฌ๋งค๋ฅผ ๋ชจ๋‘ ์ทจ์†Œํ•˜๊ณ  ์ด๋ชจํ‹ฐ์ฝ˜ ํ”Œ๋Ÿฌ์Šค ์„œ๋น„์Šค์— ๊ฐ€์ž…ํ•œ๋‹ค ํ• ์ธ์œจ์€ 10%, 20%, 30%, 40% ์ค‘ ํ•˜๋‚˜์ด๋‹ค ์ด๋ชจํ‹ฐ์ฝ˜ ํ”Œ๋Ÿฌ์Šค ์„œ๋น„์Šค์— ๊ฐ€์ž…์ž๋ฅผ ๋Š˜๋ฆฌ๋Š” ๊ฒƒ์„ ์ตœ์šฐ์„ ์œผ๋กœ ํ•˜๋ฉฐ, ์ด๋ชจํ‹ฐ์ฝ˜ ํŒ๋งค์•ก์„ ๋Š˜๋ฆฌ๋Š” ๊ฒƒ์„ ๋‘๋ฒˆ์งธ ๋ชฉํ‘œ๋กœ ํ–ˆ์„ ๋•Œ์˜ ์ด๋ชจํ‹ฐ์ฝ˜ ํ”Œ๋Ÿฌ์Šค ์„œ๋น„์Šค ๊ฐ€์ž…์ž ์ˆ˜์™€ ์ด๋ชจํ‹ฐ์ฝ˜ ๋งค์ถœ์•ก์„ 1์ฐจ์› ์ •์ˆ˜ ๋ฐฐ์—ด์— ๋‹ด์•„ ๋ฐ˜ํ™˜ํ•˜๋ผ TC input users: [[40, 10000], [25, 10000]], emoticons: [7000, 9000] ouput [1, 5400] ํ•ด๊ฒฐ๋ฐฉ๋ฒ• dfs๋ฅผ ์ด์šฉํ•ด์„œ ๋ชจ๋“  ๊ฒฝ์šฐ์˜ ์ˆ˜๋ฅผ ์™„์ „ ํƒ์ƒ‰ํ•˜์—ฌ ํ•ด๊ฒฐํ•˜์˜€๋‹ค ํ• ์ธ์œจ์˜ ๊ฒฝ์šฐ์˜ ์ˆ˜๊ฐ€ 4๊ฐ€์ง€ ๋ฐ–์— ์—†์–ด์„œ ๊ฐ€๋Šฅํ–ˆ๋˜ ์ผ์ด๋‹ค
new ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค - ํ• ์ธ ํ–‰์‚ฌ (L2)
๐Ÿง  Algorithm
1from collections import deque 2 3def solution(want, number, discount): 4 want_dict = dict() 5 answer = 0 6 7 for i in range(len(want)): 8 want_dict[want[i]] = number[i] 9 10 for i in discount[:10]: 11 if i in want_dict: 12 want_dict[i] -= 1 13 14 for i in range(0, len(discount)-9): 15 if all(map(lambda x: x <= 0, want_dict.values())): 16 answer += 1 17 18 if discount[i] in want_dict: 19 want_dict[discount[i]] += 1 20 if i+10 < len(discount) and discount[i+10] in want_dict: 21 want_dict[discount[i+10]] -= 1 22 23 return answer ๋ฌธ์ œ XYZ๋งˆํŠธ์—์„œ๋Š” ํšŒ์›์— ๊ฐ€์ž…ํ•˜๋ฉด 10์ผ๋™์•ˆ ํ• ์ธํ˜œํƒ์„ ๋ฐ›๋Š”๋‹ค ํ• ์ธํ•˜๋Š” ์ œํ’ˆ์€ ํ•˜๋ฃจ์— ํ•˜๋‚˜์”ฉ๋งŒ ๊ตฌ๋งคํ•  ์ˆ˜ ์žˆ๋‹ค ์ •ํ˜„์ด๊ฐ€ ์›ํ•˜๋Š” ์ œํ’ˆ ๋ฆฌ์ŠคํŠธ, ์›ํ•˜๋Š” ์ œํ’ˆ์˜ ์ˆ˜๋Ÿ‰ ๋ฆฌ์ŠคํŠธ, ๋งˆํŠธ์—์„œ ํ• ์ธํ•˜๋Š” ์ œํ’ˆ ๋ฆฌ์ŠคํŠธ๊ฐ€ ์ฃผ์–ด์ง„๋‹ค ์ •ํ˜„์ด๊ฐ€ ์›ํ•˜๋Š” ์ œํ’ˆ์„ ๋ชจ๋‘ ํ• ์ธ ๋ฐ›์„ ์ˆ˜ ์žˆ๋Š” ํšŒ์› ๋“ฑ๋ก ๋‚ ์งœ์˜ ์ˆ˜๋ฅผ ๊ตฌํ•˜๋ผ TC input want: [“banana”, “apple”, “rice”, “pork”, “pot”] number: [3, 2, 2, 2, 1] discount: [“chicken”, “apple”, “apple”, “banana”, “rice”, “apple”, “pork”, “banana”, “pork”, “rice”, “pot”, “banana”, “apple”, “banana”] ouput 5 ํ•ด๊ฒฐ๋ฐฉ๋ฒ• ์›ํ•˜๋Š” ์ œํ’ˆ์„ dict๋กœ ๋งŒ๋“ ๋‹ค (key: ์ œํ’ˆ์ด๋ฆ„, value: ์ˆ˜๋Ÿ‰) ์›ํ•˜๋Š” ์ œํ’ˆ - ์ฒซ๋‚ ์— ๊ฐ€์ž…ํ–ˆ์„ ๋•Œ ํ• ์ธํ•˜๋Š” ์ œํ’ˆ์„ ๊ณ„์‚ฐํ•œ๋‹ค ๋ฐ˜๋ณต๋ฌธ์„ ์ˆœํšŒํ•˜๋ฉด์„œ ํ• ์ธํ•˜๋Š” ์ œํ’ˆ์„ ๋นผ๊ณ , ํ• ์ธํ•˜๋Š” ์ œํ’ˆ์„ ๋”ํ•œ๋‹ค (์ œํ’ˆ์ด ๋” ํ•„์š”ํ•˜๋ฉด ์–‘์ˆ˜, ๋œ ํ•„์š”ํ•˜๋ฉด ์Œ์ˆ˜) 0๋ณด๋‹ค ํฐ ์ˆ˜๊ฐ€ ์žˆ์œผ๋ฉด answer์— 1์„ ๋”ํ•œ๋‹ค
new ์†Œํ”„ํŠธ์›จ์–ด ํ…Œ์ŠคํŠธ
๐ŸŽธ ๊ธฐํƒ€
๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ๊ณ ๋ คํ•˜๋Š”์ง€ ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ํ…Œ์ŠคํŠธ์˜ ๋ถ„๋ฅ˜ ๋ธ”๋ž™๋ฐ•์Šค ํ…Œ์ŠคํŠธ ํ™”์ดํŠธ๋ฐ•์Šค ํ…Œ์ŠคํŠธ ๋ชฉ์ ๊ณผ ๋ฒ”์œ„์— ๋”ฐ๋ฅธ ํ…Œ์ŠคํŠธ์˜ ๋ถ„๋ฅ˜ ์ˆ˜ํ–‰ ์ˆœ์„œ์— ๋”ฐ๋ผ ์ž‘์„ฑํ•ด๋ณด์•˜๋‹ค. 1. ๋‹จ์œ„ ํ…Œ์ŠคํŠธ (Unit Test) ๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„ ์ˆ˜์ค€(๋ชจ๋“ˆ, ํ•จ์ˆ˜, ํด๋ž˜์Šค)์˜ ํ…Œ์ŠคํŠธ 2. ํ†ตํ•ฉ ํ…Œ์ŠคํŠธ (Integration Test) ๋ชจ๋“ˆ์„ ํ†ตํ•ฉํ•˜๋Š” ๊ณผ์ •์—์„œ, ๊ฐ ๋ชจ๋“ˆ ๊ฐ„์˜ ์ธํ„ฐํŽ˜์ด์Šค์™€ ๊ด€๋ จ๋œ ๊ฒฐํ•จ์ด ์žˆ๋Š”์ง€ ํ…Œ์ŠคํŠธ Top-down : ์ƒ์œ„ ๋ชจ๋“ˆ๋ถ€ํ„ฐ ํ•˜์œ„ ๋ชจ๋“ˆ๋กœ ํ†ตํ•ฉํ•˜๋ฉฐ ํ…Œ์ŠคํŠธ Bottom-up : ํ•˜์œ„ ๋ชจ๋“ˆ๋ถ€ํ„ฐ ์ƒ์œ„ ๋ชจ๋“ˆ๋กœ ํ†ตํ•ฉํ•˜๋ฉฐ ํ…Œ์ŠคํŠธ Big-bang : ๋ชจ๋“  ๋ชจ๋“ˆ์„ ํ•œ๋ฒˆ์— ํ†ตํ•ฉํ•˜์—ฌ ํ…Œ์ŠคํŠธ Threads : ์ค‘์š” ๋ชจ๋“ˆ์„ ๋จผ์ € ๊ตฌํ˜„ํ•˜๊ณ  ํ†ตํ•ฉํ•œ ๋’ค, ๋ณด์กฐ์ ์ธ ๋ชจ๋“ˆ์„ ๊ตฌํ˜„ ํ›„ ํ†ตํ•ฉํ•˜๋Š” ๋ฐฉ์‹ 3. ์‹œ์Šคํ…œ ํ…Œ์ŠคํŠธ (System Test) ์ „์ฒด ์‹œ์Šคํ…œ์ด ์š”๊ตฌ์‚ฌํ•ญ์„ ๋งŒ์กฑํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ (HW+SW) ์ฃผ์š” ๊ด€์  ๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ ๋น„๊ธฐ๋Šฅ ํ…Œ์ŠคํŠธ : ์„ฑ๋Šฅ, ์•ˆ์ •์„ฑ, ๋ณด์•ˆ, ์‚ฌ์šฉ์„ฑ ๋“ฑ ๊ธฐํƒ€ ๋น„๊ธฐ๋Šฅ์ ์ธ ์ธก๋ฉด์„ ํ‰๊ฐ€ E2E ํ…Œ์ŠคํŠธ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ ํ˜ธํ™˜์„ฑ ํ…Œ์ŠคํŠธ : ๋‹ค์–‘ํ•œ ํ™˜๊ฒฝ์—์„œ ์˜ฌ๋ฐ”๋ฅด๊ฒŒ ์ž‘๋™ํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ 4. ์ธ์ˆ˜ ํ…Œ์ŠคํŠธ (Acceptance Test) ์‚ฌ์šฉ์ž ๊ด€์ ์—์„œ ์š”๊ตฌ์‚ฌํ•ญ์„ ๋งŒ์กฑํ•˜๋Š”์ง€ ํ…Œ์ŠคํŠธ ์‹คํ–‰ ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ํ…Œ์ŠคํŠธ์˜ ๋ถ„๋ฅ˜ ์ •์  ํ…Œ์ŠคํŠธ ๋™์  ํ…Œ์ŠคํŠธ ๋‚ด๋ถ€ ๊ตฌ์กฐ๋ฅผ ๊ณ ๋ คํ•˜๋Š”์ง€ ์—ฌ๋ถ€์— ๋”ฐ๋ฅธ ํ…Œ์ŠคํŠธ์˜ ๋ถ„๋ฅ˜ ๋ธ”๋ž™๋ฐ•์Šค ํ…Œ์ŠคํŠธ ํ™”์ดํŠธ๋ฐ•์Šค ํ…Œ์ŠคํŠธ ์ •์  ํ…Œ์ŠคํŠธ SW๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๊ณ  ํ…Œ์ŠคํŒ…ํ•˜๋Š” ๊ธฐ๋ฒ• ๋ฆฌ๋ทฐ ์—ฌ๋Ÿฌ ์ „๋ฌธ๊ฐ€๋“ค์ด ๋ชจ์—ฌ ์ฝ”๋“œ๋ฅผ ํฌํ•จํ•œ SW ๊ฐœ๋ฐœ ๋ฐ ์‚ฐ์ถœ๋ฌผ์„ ๊ฒ€ํ† ํ•˜๊ณ  ํ…Œ์ŠคํŒ…ํ•˜์—ฌ ๊ฒฐํ•จ์„ ๊ฒ€์ถœํ•˜๋Š” ๋ฐฉ๋ฒ• Inspection ์ „๋ฌธ์ ์ธ inspection team์ด ์ •ํ˜•ํ™”๋œ ๋ฐฉ์‹์œผ๋กœ defect๋ฅผ ์ฐพ๋Š” ๋ฆฌ๋ทฐ ๊ธฐ๋ฒ• Planning -> Overview -> Preparation -> Meeting(Inspection) -> Rework -> Follow-up Peer Review (Technical Review) ๊ฐœ๋ฐœํŒ€์ด ์ฃผ๋„ํ•˜์—ฌ ์ง์ ‘ ๋ชจ์—ฌ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฆฌ๋ทฐ ๊ธฐ๋ฒ• PL ๋˜๋Š” TL์ด ์ฃผ๋„ํ•˜์—ฌ ๋ฆฌ๋ทฐ ๋Œ€์ƒ์„ ์„ ์ •, ๊ฐœ๋ฐœ์ž์—๊ฒŒ ๋ฆฌ๋ทฐ ์š”์ฒญ Walkthrough Peer Review์™€ ์œ ์‚ฌํ•˜๋‚˜ ๋ฌธ์„œ ์ž‘์„ฑ์ž๊ฐ€ ์ฃผ๋„ํ•˜๋Š” ๊ฐ€๋ฒผ์šด ๋งŒ๋‚จ ํ˜•ํƒœ ์ •์  ๋ถ„์„ (๋ฌด๊ธฐ์ฒด๊ณ„SW ๊ฐœ๋ฐœ ๋ฐ ๊ด€๋ฆฌ ๋งค๋‰ด์–ผ ๊ธฐ์ค€) ์ฝ”๋”ฉ ๊ทœ์น™ MISRA-C MISRA-C++ C# Coding conventions Code conventions for the Java Programming Language CWE(Common Weakness Enumeration) ์ ๊ฒ€ ์ผ๋ฐ˜์ ์ธ SW์™€ HW์˜ ๋ณด์•ˆ ์•ฝ์ ์„ ๋‚˜์—ดํ•œ ๊ณต์‹์ ์ธ ๋ฆฌ์ŠคํŠธ CWE-658 : C์–ธ์–ด CWE-659 : C++ CWE-660 : Java Code Metric ์ ๊ฒ€ Cyclomatic Complexity : ์ œ์–ด ํ๋ฆ„ ๊ทธ๋ž˜ํ”„์˜ ๋ณต์žก๋„ Number of call levels : ์กฐ๊ฑด๋ฌธ ์ค‘์ฒฉ์˜ ๊นŠ์ด Number of function parameters Number of calling function : ํ•จ์ˆ˜๊ฐ€ ๋ช‡ ๋ฒˆ ํ˜ธ์ถœ๋˜๋Š”๊ฐ€ Number of called functions : ํ•จ์ˆ˜๋ฅผ ๋ช‡ ๋ฒˆ ํ˜ธ์ถœํ•˜๋Š”๊ฐ€ Number of Executable code lines ๋™์  ํ…Œ์ŠคํŠธ ๋ช…์„ธ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ (๋ธ”๋ž™๋ฐ•์Šค ๊ธฐ๋ฒ•) ๋™๋“ฑ ๋ถ„ํ•  ๊ฒฝ๊ณ„๊ฐ’ ๋ถ„์„ ๊ฒฐ์ • ํ…Œ์ด๋ธ” ํ…Œ์ŠคํŠธ ์ƒํƒœ ์ „์ด ํ…Œ์ŠคํŠธ ๋ถ„๋ฅ˜ ํŠธ๋ฆฌ ๊ธฐ๋ฒ• ์กฐํ•ฉ ํ…Œ์ŠคํŠธ ์‹œ๋‚˜๋ฆฌ์˜ค ํ…Œ์ŠคํŠธ … ๊ตฌ์กฐ ๊ธฐ๋ฐ˜ ํ…Œ์ŠคํŠธ (ํ™”์ดํŠธ๋ฐ•์Šค ๊ธฐ๋ฒ•) Statement Coverage Decision Coverage (Branch Coverage) Condition Coverage MC/DC Coverage Path Coverage Fuzzing ํ…Œ์ŠคํŠธ ์œ ํšจํ•œ, ์˜ˆ์ƒ์น˜ ์•Š์€ ๊ฐ’๋“ค์„ ๋ฌด์ž‘์œ„๋กœ ๋Œ€์ž…ํ•˜๋Š” ํ…Œ์ŠคํŠธ ๊ธฐ๋ฒ• ๋ณ€ํ˜• ๊ธฐ๋ฐ˜ Fuzzing (Dumb Fuzzing) ์ž…๋ ฅ ์ƒ˜ํ”Œ์„ Fuzzing ๋„๊ตฌ์— ์ œ๊ณต, Fuzzing ๋„๊ตฌ๊ฐ€ ์ด๋ฅผ ๋ณ€ํ˜•์‹œ์ผœ๊ฐ€๋ฉด์„œ ํ…Œ์ŠคํŠธ ์žฅ์  ์‰ฝ๊ณ  ๋น ๋ฅด๊ฒŒ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅ ์ž…๋ ฅ ๊ตฌ์กฐ์— ๋Œ€ํ•œ ๋ถ„์„์„ ํ•˜์ง€ ์•Š์•„๋„ ๋จ ๋‹จ์  ๋ฏธ๋ฆฌ ์ •์˜๋œ ๊ตฌ์กฐ๊ฐ€ ํ•„์š”ํ•˜๊ฑฐ๋‚˜ ์ฒดํฌ์„ฌ์ด ํฌํ•จ๋˜์–ด ์žˆ๋Š” ๊ฒฝ์šฐ ์œ ํšจํ•œ ์ž…๋ ฅ์„ ์ƒ์„ฑํ•˜๋Š”๋ฐ ์–ด๋ ค์›€์ด ์กด์žฌ ์ƒ์„ฑ ๊ธฐ๋ฐ˜ Fuzzing (Smart Fuzzing) ๋Œ€์ƒ ์‹œ์Šคํ…œ์— ์ž…๋ ฅ์‹œํ‚ฌ ๋ฐ์ดํ„ฐ๋ฅผ Fuzzing ๋„๊ตฌ๊ฐ€ ์ƒ์„ฑ ์žฅ์  ๋” ๋†’์€ Coverage๋กœ ์ด์–ด์ง€๋Š” ํ…Œ์ŠคํŠธ์ผ€์ด์Šค๋ฅผ ์ƒ์„ฑ ๋‹จ์  ์ž…๋ ฅ ๋ชจ๋ธ์— ๋Œ€ํ•œ ์ดํ•ด๋„๊ฐ€ ์„ ํ–‰๋˜์–ด์•ผ ํ•จ ๊ตฌํ˜„ ๋‚œ์ด๋„๊ฐ€ ๋†’์Œ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ (Regression Test) ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๋Š” ์†Œํ”„ํŠธ์›จ์–ด์˜ ์ƒˆ๋กœ์šด ๋ฒ„์ „์—์„œ ๊ธฐ์กด ๊ธฐ๋Šฅ์ด ์†์ƒ๋˜์ง€ ์•Š์•˜๋Š”์ง€ ํ™•์ธํ•˜๋Š” ํ…Œ์ŠคํŠธ ํšŒ๊ท€ ๋ฒ„๊ทธ(Regression Bug) : ์ด์ „์— ์กด์žฌํ•˜์ง€ ์•Š๋˜ ๋ฒ„๊ทธ๊ฐ€ ๊ธฐ๋Šฅ ์ˆ˜์ •์ด๋‚˜, ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ ์ถ”๊ฐ€๋กœ ์ธํ•ด ์ƒˆ๋กœ์šด ๋ฒ„์ „์—์„œ ๋ฐœ์ƒํ•˜๋Š” ๋ฒ„๊ทธ ํšŒ๊ท€ ํ…Œ์ŠคํŠธ๋Š” ๋ฐ˜๋ณต์ ์ธ ์ž‘์—…์ด ๋งŽ์•„ ์ž๋™ํ™” ๋„๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•˜๋Š” ๊ฒƒ์ด ํšจ์œจ์  ํšŒ๊ท€ ํ…Œ์ŠคํŠธ์˜ ์ข…๋ฅ˜ Retest all ๊ธฐ๋ฒ• : ๊ธฐ์กด์˜ ๋ชจ๋“  ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ๋‹ค์‹œ ์‹คํ–‰ํ•˜์—ฌ ์ „์ฒด ์‹œ์Šคํ…œ์„ ๊ฒ€์ฆํ•˜๋Š” ๋ฐฉ๋ฒ• Selective retest ๊ธฐ๋ฒ• : ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„์— ๋Œ€ํ•ด์„œ๋งŒ ์„ ํƒ์ ์œผ๋กœ ํ…Œ์ŠคํŠธ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” ๋ฐฉ๋ฒ• Prirority ๊ธฐ๋ฒ• : ์‹œ์Šคํ…œ์˜ ํ•ต์‹ฌ ๊ธฐ๋Šฅ์„ ์ค‘์‹ฌ์œผ๋กœ ์šฐ์„ ์ˆœ์œ„๋ฅผ ์ •ํ•˜์—ฌ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐฉ๋ฒ• FIRST ์›์น™ ๋‹จ์œ„ ํ…Œ์ŠคํŠธ์˜ 5์›์น™ Fast : ํ…Œ์ŠคํŠธ๋Š” ๋นจ๋ผ์•ผ ํ•œ๋‹ค. Independent : ํ…Œ์ŠคํŠธ๋Š” ์„œ๋กœ ๋…๋ฆฝ์ ์ด์–ด์•ผ ํ•œ๋‹ค. Repeatable : ํ…Œ์ŠคํŠธ๋Š” ์–ด๋–ค ํ™˜๊ฒฝ์—์„œ๋„ ๋ฐ˜๋ณต ๊ฐ€๋Šฅํ•ด์•ผ ํ•œ๋‹ค. Self-validating : ํ…Œ์ŠคํŠธ๋Š” ์„ฑ๊ณต ๋˜๋Š” ์‹คํŒจ์—ฌ์•ผ ํ•œ๋‹ค. (bool ๊ฐ’) Timely : ํ…Œ์ŠคํŠธ๋Š” ์ ์‹œ์— ์ž‘์„ฑํ•ด์•ผ ํ•œ๋‹ค. (์‹ค์ œ ์ฝ”๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๊ธฐ ์ „์— ์ž‘์„ฑ)
new [๋ชจ๊ฐ์ฝ”23ํ•˜๊ณ„] 02 : ๊ฒฐ๊ณผ
๐Ÿ‘จโ€๐Ÿ’ป ๋ชจ๊ฐ์ฝ”
1. ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ํ•œ ๋ฌธ์ œ ํ’€๊ธฐ ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค - ๋‹น๊ตฌ ์—ฐ์Šต (L2) ๐Ÿง  Algorithm <div class="highlight"><pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"><code class="language-python" data-lang="python"><span style="display:flex;"><span style="white-space:pre;-webkit-user-select:none;user-select:none;margin-right:0.4em;padding:0 0.4em 0 0.4em;color:#7f7f7f"> 1</span><span><span style="color:#66d9ef">def</span> <span style="color:#a6e22e">solution</span>(m, n, startX, startY, balls): </span 2. Java์˜ Testing ๊ณต๋ถ€ํ•˜๊ธฐ Spring ๊ฐœ๋… - Testing ๐Ÿƒ Spring <h2 id="unit-test-๋‹จ์œ„-ํ…Œ์ŠคํŠธ">Unit Test (๋‹จ์œ„ ํ…Œ์ŠคํŠธ)</h2> <blockquote> <p>๊ฐ€์žฅ ์ž‘์€ ๋‹จ์œ„ (ํด๋ž˜์Šค ๋˜๋Š” ๋ฉ”์†Œ๋“œ)๋ฅผ ๊ณ ๋ฆฝ์‹œ์ผœ์„œ ํ…Œ์ŠคํŠธํ•˜๋Š” ๋ฐฉ์‹</p> </blockquote> <h3 id="๊ด€๋ จ-์šฉ์–ด">๊ด€๋ จ ์šฉ์–ด</h3> <h4 id="sut-sytem-under-test">SUT (Sytem Under Test)</h4> <blockquote> <p>ํ…Œ์ŠคํŠธํ•˜๊ณ ์žํ•˜๋Š” ์ฃผ์š” ๋Œ€์ƒ์ด ๋˜๋Š” Unit</p> </blockquote> <h4 id="doc-depended-on-component">DOC (Depended On Component)</h4> <blockquote> <p>SUT๊ฐ€ ์˜์กดํ•˜๋Š” ๊ฐ์ฒด</p> </blockquote> <h4 id="test-double">Test double</h4> <blockquote> <p>DOC๋ฅผ ๋Œ€์‹ ํ•ด ์ค„ ์ˆ˜ ์žˆ๋Š” ๊ฐ์ฒด</p> </blockquote> <ul> <li>Test double์˜ ์ข…๋ฅ˜ : Moc
new [๋ชจ๊ฐ์ฝ”23ํ•˜๊ณ„] 02 : ๊ณ„ํš
๐Ÿ‘จโ€๐Ÿ’ป ๋ชจ๊ฐ์ฝ”
์˜ค๋Š˜์˜ ๋ชฉํ‘œ ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค ํ•œ ๋ฌธ์ œ ํ’€๊ธฐ Springboot Testing ๊ณต๋ถ€ํ•˜๊ธฐ
new [๋ชจ๊ฐ์ฝ”24ํ•˜๊ณ„] 05 : ๊ณ„ํš
๐Ÿ‘จโ€๐Ÿ’ป ๋ชจ๊ฐ์ฝ”
์˜ค๋Š˜์˜ ๋ชฉํ‘œ Nginx์—์„œ HTTPS ์„ค์ •ํ•˜๊ธฐ
new Fastapi, RabbitMQ, Celery ์—ฐ๋™
๐Ÿ Python
๋ฐฐ๊ฒฝ ํ…Œ์ปค ๋ถ€ํŠธ์บ ํ”„์—์„œ ํŒ€ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ ์ค‘์ด๋‹ค. ์›น์†Œ์ผ“์„ ํ†ตํ•ด ํด๋ผ์ด์–ธํŠธ๋กœ๋ถ€ํ„ฐ ๋ฐ›์€ ๋ฐ์ดํ„ฐ๋ฅผ gpt๋ฅผ ํ†ตํ•ด ์ฒ˜๋ฆฌํ•˜๊ณ , ๊ฒฐ๊ณผ๋ฅผ ๋‹ค์‹œ ํด๋ผ์ด์–ธํŠธ๋กœ ๋ณด๋‚ด๋Š” ์„œ๋น„์Šค๋ฅผ ๊ตฌํ˜„ํ•˜๊ณ  ์žˆ๋‹ค. ์—ฌ๋Ÿฌ ์‚ฌ์šฉ์ž์˜ ์š”์ฒญ์„ ์›ํ™œํ•˜๊ฒŒ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ๋ถ„์‚ฐ ๋น„๋™๊ธฐ ์‹œ์Šคํ…œ์„ ๊ตฌ์ถ•ํ•˜๋ ค๊ณ  ํ•œ๋‹ค. ๋ชฉํ‘œ Fastapi, RabbitMQ, Celery๋ฅผ ๊ฐ์ž docker ์ปจํ…Œ์ด๋„ˆ๋กœ ๊ตฌ๋™์‹œํ‚ค๊ณ  ์—ฐ๋™ํ•œ๋‹ค. docker-compose.yml 1version: '3' 2 3services: 4 rabbitmq: 5 image: rabbitmq:3 6 ports: 7 - "5672:5672" # RabbitMQ์˜ AMQP ํฌํŠธ 8 - "15672:15672" # RabbitMQ ๊ด€๋ฆฌ ์ธํ„ฐํŽ˜์ด์Šค ํฌํŠธ 9 volumes: 10 - rabbitmq_data:/var/lib/rabbitmq 11 expose: 12 - "5672" 13 - "15672" 14 15 celery_worker: 16 build: 17 context: . 18 dockerfile: Dockerfile.worker 19 command: celery -A utils.celery_worker worker --loglevel=info 20 working_dir: /app 21 volumes: 22 - ./app/utils:/app/utils 23 environment: 24 - CELERY_BROKER_URL=amqp://guest:guest@rabbitmq:5672// 25 depends_on: 26 - rabbitmq 27 28 celery_beat: 29 image: celery:4 30 command: celery -A celery_beat beat --loglevel=info 31 working_dir: /app 32 environment: 33 - CELERY_BROKER_URL=amqp://guest:guest@rabbitmq:5672// 34 volumes: 35 - ./app/utils:/app 36 depends_on: 37 - rabbitmq 38 39 web: 40 image: python:slim 41 working_dir: /app 42 # interactive mode 43 stdin_open: true 44 # tty mode 45 tty: true 46 environment: 47 - CELERY_BROKER_URL=amqp://guest:guest@rabbitmq:5672// 48 volumes: 49 - ./app:/app 50 ports: 51 - "8000:8000" 52 depends_on: 53 - rabbitmq 54 - celery_worker 55 - celery_beat 56 57volumes: 58 rabbitmq_data: Celery worker์—๋งŒ Dockerfile.worker๋ฅผ ์ด๋ฏธ์ง€๋กœ ์‚ฌ์šฉํ•œ ์ด์œ  worker์— ์ถ”๊ฐ€์ ์œผ๋กœ python ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•ด์•ผํ•จ Celery ๊ณต์‹ ๋„์ปค ์ด๋ฏธ์ง€๊ฐ€ deprecated ๋˜์—ˆ์Œ. Fastapi๋Š” ์‹œ๊ฐ„ ๊ด€๊ณ„์ƒ ๋”ฐ๋กœ ์ด๋ฏธ์ง€๋ฅผ ๋งŒ๋“ค์ง€ ์•Š๊ณ  python:slim ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค. Dockerfile.worker 1FROM python:slim 2 3# ํ•„์š”ํ•œ ํŒจํ‚ค์ง€ ์„ค์น˜ 4# ffmpeg๊ฐ€ ํ•„์š”ํ•ด์„œ ์ถ”๊ฐ€ํ•˜์˜€๋‹ค 5RUN apt-get update && \ 6apt-get install -y --no-install-recommends gcc libpq-dev ffmpeg && \ 7rm -rf /var/lib/apt/lists/* 8 9# ํ•„์š”ํ•œ ํŒŒ์ด์ฌ ํŒจํ‚ค์ง€ ์„ค์น˜ 10COPY requirements_celery_worker.txt ./ 11RUN pip install --no-cache-dir -r requirements_celery_worker.txt celery_worker.py 1import os 2from celery import Celery 3 4broker_url = os.getenv('CELERY_BROKER_URL') 5app = Celery('worker', broker=broker_url, backend="rpc://") 6 7@app.task 8def add(x, y): 9 return x + y broker_url์€ RabbitMQ์˜ AMQP ์ฃผ์†Œ๋ฅผ ์˜๋ฏธํ•œ๋‹ค. backend๋Š” ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•œ ๋ฐฑ์—”๋“œ๋กœ RabbitMQ๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. Celery worker ์‚ฌ์šฉ ๋ฐฉ๋ฒ• 1from celery_worker import add 2 3# task๋ฅผ ๋น„๋™๊ธฐ๋กœ ์‹คํ–‰ 4result = add.delay(4, 4) 5 6# apply_async๋Š” delay์™€ ๋™์ผํ•œ ๊ธฐ๋Šฅ ์ˆ˜ํ–‰ 7# delay์™€ ๋‹ฌ๋ฆฌ ์ถ”๊ฐ€๋กœ ์—ฌ๋Ÿฌ ์˜ต์…˜์„ ์„ค์ • ๊ฐ€๋Šฅ 8result = add.apply_async((4, 4)) 9 10# ๊ฒฐ๊ณผ๋ฅผ ๋ฐ›๊ธฐ ์œ„ํ•ด get()์„ ์‚ฌ์šฉ, ๋ธ”๋กœํ‚น ํ˜ธ์ถœ 11result.get() 12 13# ์ž‘์—…์ด ์™„๋ฃŒ๋˜์—ˆ๋Š”์ง€ ํ™•์—… 14result.ready() 15 16# ์ž‘์—…์ด ์‹คํŒจํ–ˆ๋Š”์ง€ ํ™•์ธ 17result.successful() 18# or 19result.failed() 20 21# ์ž‘์—…์˜ ์ƒํƒœ ํ™•์ธ (PENDING, STARTED, SUCCESS, FAILURE) 22result.state()
new ์ธ๊ฐ„-์ปดํ“จํ„ฐ ์ƒํ˜ธ์ž‘์šฉ
๐Ÿซ ํ•™๊ณผ ๊ณต๋ถ€
Design Techniques Contextual Inquiry ์‚ฌ์šฉ์ž์˜ ํ™˜๊ฒฝ์—์„œ ์‚ฌ์šฉ์ž์˜ ํ–‰๋™์„ ๊ด€์ฐฐ Design Funnel ์•„์ด๋””์–ด๋ฅผ ํ™•์žฅํ•จ๊ณผ ๋™์‹œ์— ์ถ•์†Œ ์‹œํ‚ด์œผ๋กœ์„œ ๊ฒฐ๊ณผ ๋„์ถœ Double Diamond Discover -> Define -> Develop -> Deliver Storyboarding ์‹œ๋‚˜๋ฆฌ์˜ค๋ฅผ ๊ทธ๋ฆผ์œผ๋กœ ํ‘œํ˜„ Prototyping ๋””์ž์ธ์„ ํ‘œํ˜„ํ•˜๋Š” ์†Œํ”„ํŠธ์›จ์–ด๋กœ ๊ตฌํ˜„ ์ข…๋ฅ˜: Low-fidelity(์ถฉ์‹ค๋„๊ฐ€ ๋‚ฎ์Œ), High-fidelity(์ถฉ์‹ค๋„๊ฐ€ ๋†’์Œ) User Testing In-lab vs On-site Moderated vs Unmoderated : Exploratory vs Assessment Presentation & Communication Needfinding (์š”๊ตฌ์‚ฌํ•ญ ๋„์ถœ) ์šฉ์–ด UI (User Interface) ์ œํ’ˆ์˜ ์‹œ๊ฐ์ ์ธ ์š”์†Œ UX (User Experience) ์ œํ’ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ๋А๋ผ๋Š” ๊ฒฝํ—˜ CX (Customer Experience) ๊ณ ๊ฐ์ด ์ œํ’ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ๊ณผ์ •์—์„œ ๋А๋ผ๋Š” ์ „๋ฐ˜์ ์ธ ๊ฒฝํ—˜, ์ƒํ’ˆ ๋˜๋Š” ์„œ๋น„์Šค์˜ ๊ตฌ๋งค, ์‚ฌ์šฉ ์—ฌ๋ถ€๋ฅผ ๊ฒฐ์ •์ง“๋Š” ์š”์†Œ SD (Service Design) ์„œ๋น„์Šค๋ฅผ ๋””์ž์ธํ•˜๋Š” ๊ฒƒ HCI (Human-Computer Interaction) ์—ฌ๋Ÿฌ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ์กฐํ•ฉํ•˜์—ฌ ์‚ฌ์šฉ์ž์—๊ฒŒ ์ตœ๊ณ ์˜ ๊ฒฝํ—˜์„ ์ œ๊ณตํ•˜๊ธฐ ์œ„ํ•ด ์„ ํƒ, ์ œ์ž‘, ๊ฒฐํ•ฉํ•˜๋Š” ๊ฒƒ SRS (Software Requirement Specification) ์†Œํ”„ํŠธ์›จ์–ด ์š”๊ตฌ์‚ฌํ•ญ ๋ช…์„ธ์„œ User Requirements, Functional Requirements, Interface Requirements, Performance Requirements… SRS๋ฅผ ๋ฌธ์„œํ™”ํ•˜๊ธฐ์ „์— ์‚ฌ์šฉ์ž๋ฅผ ์ดํ•ดํ•˜๋Š” ๊ฒƒ์ด ์ค‘์š” ์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ ์ดํ•ด ๋‹ค์–‘ํ•œ ์‚ฌ์šฉ์ž์˜ ํŠน์„ฑ์„ ์ดํ•ด : ์—ญํ• , ๊ฐœ์„ฑ ์ดํ•ด๊ด€๊ณ„์ž(stakeholders)๋ฅผ ๊ณ ๋ ค First degree : ์ง์ ‘์ ์œผ๋กœ ์ œํ’ˆ์„ ์‚ฌ์šฉํ•˜๋Š” ์‚ฌ๋žŒ Second degree : ์ œํ’ˆ์˜ ๊ฒฐ๊ณผ์— ์˜ํ–ฅ์„ ๋ฐ›๋Š” ์‚ฌ๋žŒ Third degree : ์„œ๋น„์Šค๋ฅผ ์„ค์น˜, ๋ฐฐํฌํ•˜๋Š” ์‚ฌ๋žŒ ๋˜๋Š” ๊ธฐ๋ฐ˜ ์‹œ์Šคํ…œ ์‚ฌ์šฉ์ž ๋ชฉ์  ํŒŒ์•… Identify the goals involved in the problem Decompose them into subtasks Abstract into goals Contextual Inquiry (์ƒํ™ฉ์  ์กฐ์‚ฌ) Context : ์‚ฌ์šฉ์ž์˜ ํ™˜๊ฒฝ ๊ด€์ฐฐ, ์ถ”์ƒํ™” ๊ธˆ์ง€ Partnership : ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ณต๊ฐ, ์‚ฌ์šฉ์ž์—๊ฒŒ ํ–‰๋™๊ณผ ๊ทธ ์ด์œ ๋ฅผ ์งˆ๋ฌธ Interpretation : ์‚ฌ์šฉ์ž์— ๋Œ€ํ•œ ํ•ด์„์„ ์‚ฌ์šฉ์ž์—๊ฒŒ ๊ณต์œ , ์‚ฌ์šฉ์ž์˜ ํ”ผ๋“œ๋ฐฑ์„ ๋ฐ›์Œ Focus : ๋ชฉํ‘œ์— ์ง‘์ค‘ The master-apprentice model (๋„์ œ์‹ ๋ชจ๋ธ) : ์‚ฌ์šฉ์ž(์„ ์ƒ), ๊ด€์ฐฐ์ž(ํ•™์ƒ) Contextual Inquiry๊ฐ€ ์ ์ ˆํ•˜์ง€ ์•Š์„ ๋•Œ Longidual study : ์‚ฌ์šฉ์ž์˜ ํ–‰๋™์„ ์žฅ๊ธฐ๊ฐ„ ๊ด€์ฐฐํ•ด์•ผํ•  ๋•Œ Sporadic behavior : ์‚ฌ์šฉ์ž์˜ ํ–‰๋™์ด ๋ถˆ๊ทœ์น™ํ•  ๋•Œ Large target : ์‚ฌ์šฉ์ž์˜ ๋ฒ”์œ„๊ฐ€ ๊ด‘๋ฒ”์œ„ ํ•  ๋•Œ Diary Study ์‚ฌ์šฉ์ž๊ฐ€ ์ผ์ƒ์ ์œผ๋กœ ํ•˜๋Š” ์ผ์„ ๊ธฐ๋กํ•˜๋Š” ๊ฒƒ ESM (Experience Sampling Method) ์ˆœ๊ฐ„์ ์ธ ํ™œ๋™๊ณผ ๊ฒฝํ—˜์— ์ดˆ์ ์„ ๋งž์ถฐ ๊ธฐ๋ก EMA (Ecological Momentary Assessment) ์‹ฌ๋ฆฌ์  ํ˜„์ƒ์˜ ๊ถค์ , ๋ถ„์‚ฐ, ๋ณ€๋™, ์—ญํ•™์— ์ดˆ์ ์„ ๋งž์ถฐ ๊ธฐ๋ก Survey Participatory Design ์‚ฌ์šฉ์ž๊ฐ€ ์ง์ ‘ ๋””์ž์ธ์— ์ฐธ์—ฌํ•˜๋Š” ๊ฒƒ Affinity Diagram (์œ ์‚ฌ๋„ ๋‹ค์ด์–ด๊ทธ๋žจ) ์ˆ˜์ง‘ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ๋ถ„๋ฅ˜ํ•˜๋Š” ๊ฒƒ Persona ์‚ฌ์šฉ์ž๋ฅผ ๋Œ€ํ‘œํ•˜๋Š” ๊ฐ€์ƒ์˜ ์ธ๋ฌผ Learnability ์ƒˆ๋กœ์šด UI๋ฅผ ๋ฐฐ์šฐ๋Š” ๋ฐฉ๋ฒ• Learning by Doing Learning by Watching Recognition vs Recall Recognition : ์‹œ๊ฐ์  ์š”์†Œ๋ฅผ ๋ณด๊ณ  ์ธ์ง€ํ•˜๋Š” ๊ฒƒ Recall : ๊ธฐ์–ต์„ ํ†ตํ•ด ์ธ์ง€ํ•˜๋Š” ๊ฒƒ Interaction style Command Language ์ธ๊ณต ์–ธ์–ด์˜ ๋ช…๋ น์–ด๋ฅผ ์ž…๋ ฅ Self Disclosure (์ž๊ธฐ ๊ณต๊ฐœ) : ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ช…๋ น์–ด๋ฅผ ์‹œ๊ฐ์ ์œผ๋กœ ํ‘œํ˜„ Menus and Forms Direct Manipulation ์ฆ‰๊ฐ์ ์œผ๋กœ ๋ฐ˜์‘ ์‹œ๊ฐ์  ํ‘œํ˜„์„ ํ†ตํ•ด ์ƒํ˜ธ์ž‘์šฉ Speech Dialog Mental Model ์‚ฌ๋žŒ๋“ค์ด ์ž๊ธฐ ์ž์‹ , ๋‹ค๋ฅธ ์‚ฌ๋žŒ, ํ™˜๊ฒฝ, ์ž์‹ ์ด ์ƒํ˜ธ์ž‘์šฉํ•˜๋Š” ์‚ฌ๋ฌผ๋“ค์— ๋Œ€ํ•ด ๊ฐ–๋Š” ๋ชจํ˜• ๊ด€์ฐฐ, ์ธํ„ฐ๋ทฐ, ์ž‘์—… ๋ถ„์„์ด ํ•„์š”ํ•˜๋‹ค Conceptual Model ์ œํ’ˆ์ด ์–ด๋– ํ•œ ์›๋ฆฌ๋‚˜ ๋ฐฉ์‹์œผ๋กœ ์ž‘๋™ํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ์ดํ•ด Content strategy : ๊ฐ ํŽ˜์ด์ง€์— ๋‚˜ํƒ€๋‚˜๋Š” ๋‚ด์šฉ์˜ ๊ทœ์น™์ด๋‚˜ ๊ฐœ๋…์ด ์กด์žฌํ•˜๋Š”๊ฐ€? Channel starategy : ์ผ๊ด€์ ์ธ ๊ฒฝํ—˜, ์ง€์†์ ์ธ ๊ฒฝํ—˜, ์ƒํ˜ธ ๋ณด์™„์ ์ธ ๊ฒฝํ—˜์„ ๋งŒ๋“ค์–ด๋‚ด๋Š”๊ฐ€? Interaction models : ๋ณดํŽธ์ ์ธ ํŒจํ„ด์„ ์‚ฌ์šฉํ–ˆ๋Š”๊ฐ€?
new ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ฐ MSA ํŠน๊ฐ• 1์ผ์ฐจ : ํด๋ผ์šฐ๋“œ ์ปดํ“จํŒ… ๊ฐœ๋… ๋ฐ ์—ญ์‚ฌ
๐Ÿซ ํ•™๊ณผ ๊ณต๋ถ€
ํด๋ผ์šฐ๋“œ ์ œ๋Œ€๋กœ ์ดํ•ดํ•˜๊ธฐ ํด๋ผ์šฐ๋“œ๋ž€ ๊ฐœ์ธ์ด ๊ฐ€์ง„ ๋‹จ๋ง๊ธฐ๋ฅผ ํ†ตํ•ด์„œ๋Š” ์ฃผ๋กœ ์ž…/์ถœ๋ ฅ ์ž‘์—…๋งŒ ์ด๋ฃจ์–ด์ง€๊ณ , ์ •๋ณด๋ถ„์„ ๋ฐ ์ฒ˜๋ฆฌ, ์ €์žฅ, ๊ด€๋ฆฌ ์œ ํ†ต ๋“ฑ์˜ ์ž‘์—…์€ ํด๋ผ์šฐ๋“œ๋ผ๊ณ  ๋ถˆ๋ฆฌ๋Š” ์ œ3์˜ ๊ณต๊ฐ„์—์„œ ์ด๋ฃจ์–ด์ง€๋Š” ์ปดํ“จํŒ… ์‹œ์Šคํ…œ ํ˜•ํƒœ ํด๋ผ์šฐ๋“œ ์ปดํ“จํŒ…์ด ํ•„์š”ํ•œ ์ด์œ  ๋น„์šฉ์ ˆ๊ฐ ์†๋„ํ–ฅ์ƒ ํ™•์žฅ์„ฑ ์ƒ์‚ฐ์„ฑ ํด๋ผ์šฐ๋“œ ์ปดํ“จํŒ… ์„œ๋น„์Šค๋ชจ๋ธ Infrastructure as a Service (IaaS) : IT๋ฆฌ์†Œ์Šค์— ๋Œ€ํ•œ ์œ ์—ฐ์„ฑ๊ณผ ๊ด€๋ฆฌ ์ œ์–ด ๊ธฐ๋Šฅ์„ ์ œ๊ณต GCE, AWS, Azure Platform as a Service (Paas) : ๋นŒ๋“œ ๋ฐ ๋ฐฐํฌ๋ฅผ ์œ„ํ•œ ํ™˜๊ฒฝ์ด ์‚ฌ์šฉ์ž์—๊ฒŒ ์ œ๊ณต Openshift, Github, docker, kubernetes Software as a a Service (Saas) : ์™„์ „ํ•œ ์ œํ’ˆ ์ œ๊ณต GShift ๋น„๊ต On-site < Iaas < Paas < Saas ์›นํ˜ธ์ŠคํŒ… vs ์„œ๋ฒ„ํ˜ธ์ŠคํŒ… vs ํด๋ผ์šฐ๋“œ ์ฐจ์ด์  ์›นํ˜ธ์ŠคํŒ… : ํ˜ธ์ŠคํŒ… ์—…์ฒด์˜ ์„œ๋ฒ„ ์ค‘ ์ผ๋ถ€๋งŒ ์ž„๋Œ€ํ•˜์—ฌ ์‚ฌ์šฉ ํ™ˆํŽ˜์ด์ง€ ์šด์˜ ์„œ๋ฒ„ํ˜ธ์ŠคํŒ… : ํ˜ธ์ŠคํŒ… ์—…์ฒด์˜ ๋ฌผ๋ฆฌ ์„œ๋ฒ„๋ฅผ ๋‹จ๋…์œผ๋กœ ์ž„๋Œ€/๊ตฌ๋งคํ•˜์—ฌ ์‚ฌ์šฉ ERP, ์ธํŠธ๋ผ๋„ท ๋“ฑ ์šด์˜ ํด๋ผ์šฐ๋“œ ๋‹จ๊ธฐ ์ด๋ฒคํŠธ ๋“ฑ ์œ ๋™์ ์ธ ์„œ๋น„์Šค ์šด์˜ On-premise๋ž€ ์ž์ฒด์ ์œผ๋กœ ๋ณด์œ ํ•œ ์ „์‚ฐ์‹ค์— ์ง์ ‘ ์„ค์น˜ํ•ด ์šด์˜ํ•˜๋Š” ๋ฐฉ์‹ Private, Public, Hybrid Cloud ๋น„๊ต Private cloud ์ธํ”„๋ผ๊ฐ€ ์กฐ์ง ์ „์šฉ์ธ ํด๋ผ์šฐ๋“œ ์ปดํ“จํŒ… ๋ชจ๋ธ ํ•ด๋‹น ์‚ฌ์šฉ์ž ๋˜๋Š” ๊ทธ๋ฃน์˜ ๋ฐฉํ™”๋ฒฝ์œผ๋กœ ๋ณดํ˜ธ๋œ๋‹ค Public cloud ์ตœ์ข… ์‚ฌ์šฉ์ž๊ฐ€ ์†Œ์œ ํ•˜์ง€ ์•Š์€ IT์ธํ”„๋ผ์—์„œ ์ƒ์„ฑ๋˜๋Š” ํด๋ผ์šฐ๋“œ ํ™˜๊ฒฝ Alibaba Cloud, AWS, GCP, IBM Cloud, Microsft Azure ๋“ฑ์ด ์žˆ๋‹ค Hybrid cloud ๋‹จ์ผ ITํ™˜๊ฒฝ ์ฒ˜๋Ÿผ ๋ณด์ด์ง€๋งŒ ์‹ค์ œ๋กœ๋Š” ์—ฌ๋Ÿฌ ํ™˜๊ฒฝ์ด ์—ฐ๊ฒฐ๋œ ํ˜•ํƒœ ์—…์ฒด๋ณ„ ํด๋ผ์šฐ๋“œ ์‹œ์žฅ GCP, Azure, AWS ํด๋ผ์šฐ๋“œ ๊ด€๋ จ ์ง๊ตฐ ํด๋ผ์šฐ๋“œ ์—”์ง€๋‹ˆ์–ด ํด๋ผ์šฐ๋“œ ์‹œ์Šคํ…œ ์—”์ง€๋‹ˆ์–ด ํด๋ผ์šฐ๋“œ ์ธํ”„๋ผ ๋ณด์•ˆ ๋‹ด๋‹น์ž ๋ฐ๋ธŒ์˜ต์Šค ํด๋ผ์šฐ๋“œ ๋ฐฑ์—”๋“œ ๊ฐœ๋ฐœ์ž
new ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ๋ฐ MSA ํŠน๊ฐ• 3์ผ์ฐจ : ๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ• ์‹ค์Šต (ELK), kubernetes
๐Ÿซ ํ•™๊ณผ ๊ณต๋ถ€
๋ชจ๋‹ˆํ„ฐ๋ง ์‹œ์Šคํ…œ ๊ตฌ์ถ• ์‹ค์Šต (ELK) ELK๋ž€ ELK๋Š” Elasticsearch, Logstash ๋ฐ Kibana : ์˜คํ”ˆ ์†Œ์Šค ํ”„๋กœ์ ํŠธ ์„ธ ๊ฐœ์˜ ๋จธ๋ฆฌ๊ธ€ Elasticserach๋Š” ๊ฒ€์ƒ‰ ๋ฐ ๋ถ„์„ ์—”์ง„ Logstash๋Š” ์—ฌ๋Ÿฌ ์†Œ์Šค์—์„œ ๋™์‹œ์— ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘ํ•˜์—ฌ ๋ณ€ํ™˜ํ•œ ํ›„ Elasticsearch ๊ฐ™์€ “stash"๋กœ ์ „์†กํ•˜๋Š” ์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ Kibana๋Š” ์‚ฌ์šฉ์ž๊ฐ€ Elasticsearch์—์„œ ์ฐจํŠธ์™€ ๊ทธ๋ž˜ํ”„๋ฅผ ์ด์šฉํ•ด ๋ฐ์ดํ„ฐ๋ฅผ ์‹œ๊ฐํ™” Kibana Elasticsearch์— ์žˆ๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ์‹œ๊ฐํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ์›น ๋ธŒ๋ผ์šฐ์ € ๊ธฐ๋ฐ˜์˜ ์‹œ๊ฐํ™” ํ”Œ๋žซํผ Elasticsearch์— ์žˆ๋Š” ์ธ๋ฑ์Šค์˜ ํŒจํ„ด์„ ์ฐพ์•„์„œ, ๋ฐ์ดํ„ฐ๋ฅผ ํ™•์ธํ•˜๊ฑฐ๋‚˜, ์‹œ๊ฐํ™”ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค Logstash ์„œ๋ฒ„ ๋ฐ์ดํ„ฐ๋ฅผ ์ˆ˜์ง‘, ๋ณ€ํ™˜, ์ „์†กํ•˜๋Š” ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ํŒŒ์ดํ”„๋ผ์ธ์œผ๋กœ, Jruby(JVM ๊ธฐ๋ฐ˜ Ruby)๋กœ ๊ฐœ๋ฐœ๋˜์—ˆ๋‹ค ๋ฐ์ดํ„ฐ ์ฒ˜๋ฆฌ ๊ณผ์ •์€ input, filter, out์˜ ์„ธ ๋‹จ๊ณ„๋กœ ๊ตฌ์„ฑ๋œ๋‹ค Docker Compose Docker Compose alias ์„ค์ • 1alias dco="docker-compose" 2... Docker-Compose ํŒŒ์ผ docker-compose.yml version:‘3.2’ // docker-compose file format / ๊ฐ ๋ฒ„์ „ ๋ณ„๋กœ ์ œ๊ณต api๊ฐ€ ๋‹ค๋ฅด๋‹ค services: // container ์„œ๋น„์Šค ๊ทธ๋ฃน ports: // ํฌํŠธ ์ง€์ • Host Port : Container Port depends_on: // ์„œ๋น„์Šค๊ฐ„ ์˜์กด๊ด€๊ณ„ ์„ค์ • ELK ์‹ค์Šต docker-compose ์ปจํ…Œ์ด๋„ˆ ์ƒ์„ฑ ๋ฐ ์‹คํ–‰ docker-compose up docker-compose ์ปจํ…Œ์ด๋„ˆ ์ •์ง€ ๋ฐ ์‚ญ์ œ docker-compose down docker-compose ์ปจํ…Œ์ด๋„ˆ ๋ชฉ๋ก ์กฐํšŒ docker-compose ps docker-compose ์ปจํ…Œ์ด๋„ˆ ๋กœ๊ทธ ์กฐํšŒ docker-compose logs ElasticSearch ํ™•์ธ open http://localhost:9200/_cat/indices Kibana ํ™•์ธ http://localhost:5601/app/kibana container ์ ‘์† docker-compose exec logstash sh ์ฐธ๊ณ  : PoC (Proof of Concept) ์ƒˆ๋กœ์šด ํ”„๋กœ์ ํŠธ๊ฐ€ ์‹ค์ œ๋กœ ์‹คํ˜„ ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋Š”๊ฐ€, ํšจ๊ณผ์™€ ํšจ์šฉ, ๊ธฐ์ˆ ์ ์ธ ๊ด€์ ์—์„œ๋ถ€ํ„ฐ ๊ฒ€์ฆ์„ ํ•˜๋Š” ๊ณผ์ • Kubernetes ์ดํ•ดํ•˜๊ธฐ Kubernetes๊ฐ€ ํ•„์š”ํ•œ ์ด์œ  ๋Œ€๋ถ€๋ถ„์˜ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ : ํ•˜๋‚˜์˜ ํ”„๋กœ์„ธ์Šค ๋˜๋Š” ๋ช‡๊ฐœ์˜ ์„œ๋ฒ„์— ๋ถ„์‚ฐ๋œ ํ”„๋กœ์„ธ์Šค๋กœ ์‹คํ–‰๋˜๋Š” ๊ฑฐ๋Œ€ํ•œ ๋ชจ๋†€๋ฆฌ์Šค ์ด๋Ÿฌํ•œ ์‹œ์Šคํ…œ์€ ๋ฆด๋ฆฌ์ฆˆ ์ฃผ๊ธฐ๊ฐ€ ๋А๋ฆฌ๊ณ  ์—…๋ฐ์ดํŠธ๊ฐ€ ์ž์ฃผ ์ผ์–ด๋‚˜์ง€ ์•Š์Œ ๊ฐœ๋ฐœ์ž๋Š” ์ „์ฒด ๋ฆด๋ฆฌ์ฆˆ ์ฃผ๊ธฐ๊ฐ€ ๋๋‚ ๋•Œ ๋งˆ๋‹ค ์ „์ฒด ์‹œ์Šคํ…œ์„ ํŒจํ‚ค์ง•ํ•˜๊ณ  ์šด์˜ํŒ€์€ ์ด๋ฅผ ๋ฐฐํฌํ•˜๊ณ  ๋ชจ๋‹ˆํ„ฐ๋งํ•œ๋‹ค ์šด์˜ํŒ€์€ ํ•˜๋“œ์›จ์–ด ์žฅ์• ๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์ด๋ฅผ ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ์„œ๋ฒ„๋กœ ์ง์ ‘ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํ•œ๋‹ค ๊ฑฐ๋Œ€ํ•œ ๋ชจ๋†€๋ฆฌ์Šค ๋ ˆ๊ฑฐ์‹œ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์ ์  MSA๋กœ ๋” ์ž‘์€ ๊ตฌ์„ฑ ์š”์†Œ๋กœ ์„ธ๋ถ„ํ™” ๋งˆ์ดํฌ๋กœ ์„œ๋น„์Šค๋Š” ์„œ๋กœ ๋ถ„๋ฆฌ๋ผ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ๊ฐœ๋ณ„์ ์œผ๋กœ ๊ฐœ๋ฐœ, ๋ฐฐํฌ, ์—…๋ฐ์ดํŠธ, ํ™•์žฅ ๊ฐ€๋Šฅ ๋ฐฐํฌ ๊ฐ€๋Šฅํ•œ ๊ตฌ์„ฑ์š”์†Œ๊ฐ€ ๋งŽ์•„์ง€๊ณ  ๋ฐ์ดํ„ฐ์„ผํ„ฐ ๊ทœ๋ชจ๊ฐ€ ์ปค์ง€๋ฉด์„œ ์ „์ฒด ์‹œ์Šคํ…œ์„ ๊ตฌ์„ฑ, ๊ด€๋ฆฌ, ์œ ์ง€ํ•˜๊ธฐ๋Š” ์‰ฝ์ง€ ์•Š์€ ์ผ ๋ฆฌ์†Œ์Šค ํ™œ์šฉ์„ ๋†’์ด๊ณ  ํ•˜๋“œ์›จ์–ด ๋น„์šฉ์„ ๋‚ฎ์ถ”๊ณ  ๊ฐ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ๋ฐฐ์น˜ํ•  ์œ„์น˜๋ฅผ ํŒŒ์•…ํ•˜๊ธฐ์— ๋„ˆ๋ฌด ์–ด๋ ค์›€ ์ˆ˜๋™์œผ๋กœ ๋ถˆ๊ฐ€๋Šฅ ์ด๋Ÿฐ ๊ตฌ์„ฑ์š”์†Œ๋ฅผ ์ž๋™์œผ๋กœ ์Šค์ผ€์ฅด๋งํ•˜๊ณ  ๊ตฌ์„ฑ, ๊ด€๋ฆฌ, ์žฅ์• ์ฒ˜๋ฆฌ๋ฅผ ํฌํ•จํ•˜๋Š” ์ž๋™ํ™”๊ฐ€ ํ•„์š” => ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๊ฐ€ ํ•„์š”ํ•œ ์ด์œ  ๋งˆ์ดํฌ๋กœ์„œ๋น„์Šค ๋ฐฐํฌ ๋‹จ์  ๊ฐ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ€ ๋งŽ์•„์ง€๋ฉด ๋ฐฐํฌ ์กฐํ•ฉ์˜ ์ˆ˜ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ตฌ์„ฑ ์š”์†Œ๊ฐ„์˜ ์ƒํ˜ธ ์ข…์†์„ฑ ์ˆ˜๊ฐ€ ํ›จ์”ฌ ๋งŽ์•„์ง€๋ฏ€๋กœ ๋ฐฐํฌ ๊ด€๋ จ ๊ฒฐ์ •์ด ์–ด๋ ต๋‹ค ์—ฌ๋Ÿฌ ํ”„๋กœ์„ธ์Šค์™€ ์‹œ์Šคํ…œ์— ๋ถ„์‚ฐ๋ผ ์žˆ๊ธฐ ๋•Œ๋ฌธ์— ์‹คํ–‰ ํ˜ธ์ถœ์„ ๋””๋ฒ„๊น…ํ•˜๊ณ  ์ถ”์ ํ•˜๊ธฐ ์–ด๋ ต๋‹ค Kubernetes ๊ฐœ๋… ๊ตฌ๊ธ€์€ Borg๋ผ๋Š” ์‹œ์Šคํ…œ์„ ๊ฐœ๋ฐœํ•ด ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜ ๊ฐœ๋ฐœ์ž์™€ ์‹œ์Šคํ…œ ๊ด€๋ฆฌ์ž๊ฐ€ ์ˆ˜์ฒœ ๊ฐœ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ ์„œ๋น„์Šค๋ฅผ ๊ด€๋ฆฌํ•˜๋Š”๋ฐ ๋„์›€์„ ์ค€๋‹ค ๊ตฌ๊ธ€ 10๋…„๊ฐ„ ๊ฒฝํ—˜์„ ๋ฐ”ํƒ•์œผ๋กœ 2014๋…„์— kubernetes ํ”„๋กœ์ ํŠธ๋ฅผ ์˜คํ”ˆ์†Œ์Šคํ™” ํ•œ๋‹ค ๋ณ„๋ช…์€ k8s์ด๋‹ค ์ปจํ…Œ์ด๋„ˆ๋ฅผ ์“ฐ๋Š” ์ด์œ  ๊ฒฝ๋Ÿ‰, ์ด์‹์„ฑ ๋ฐ ํ”Œ๋žซํผ ๋…๋ฆฝ์„ฑ, ์ตœ์‹ ํ˜• ๊ฐœ๋ฐœ ๋ฐ ์•„ํ‚คํ…์ฒ˜ ์ง€์›, ํ™œ์šฉ๋„ ํ–ฅ Kubernetes ์•„ํ‚คํ…์ฒ˜ ๋งˆ์Šคํ„ฐ ๋…ธ๋“œ : ์ „์ฒด ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์‹œ์Šคํ…œ์„ ์ œ์–ดํ•˜๊ณ  ๊ด€๋ฆฌํ•˜๋Š” ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค ์ปจํŠธ๋กค ํ”Œ๋ ˆ์ธ์„ ์‹คํ–‰ ์›Œ์ปค ๋…ธ๋“œ : ์‹ค์ œ ๋ฐฐํฌ๋˜๋Š” ์ปจํ…Œ์ด๋„ˆ ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜์„ ์‹คํ–‰ kubernetes ์‹ค์Šต 1 minikube start kubectl run ntest --image=develo0100/node --port 8080 curl localhost:8080 kubernetes pod ์†Œ๊ฐœ ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค๋Š” ๊ฐœ๋ณ„ ์ปจํ…Œ์ด๋„ˆ๋“ค์„ ์ง์ ‘ ๋‹ค๋ฃจ์ง€ ์•Š๊ณ , ํ•จ๊ป˜ ๋ฐฐ์น˜๋œ ๋‹ค์ˆ˜์˜ ์ปจํ…Œ์ด๋„ˆ๋ผ๋Š” ๊ฐœ๋…์„ ์‚ฌ์šฉํ•œ๋‹ค kubernetes ๋ฐฑ๊ทธ๋ผ์šด๋“œ ๋™์ž‘ ๋„์ปค ๋ฐ๋ชฌ์ด ์‹คํ–‰ ์ค‘์ธ ๋‹ค๋ฅธ ์›Œ์ปค ๋…ธ๋“œ์—์„œ ์ปจํ…Œ์ด๋„ˆ ์ด๋ฏธ์ง€๋กœ ์ ‘๊ทผํ•˜๋ ค๋ฉด ๋„์ปคํ—ˆ๋ธŒ์— ์ด๋ฏธ์ง€๊ฐ€ ์˜ฌ๋ ค์ ธ์žˆ์–ด์•ผ ํ•œ๋‹ค kubectl ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•˜๋ฉด ์ฟ ๋ฒ„๋„คํ‹ฐ์Šค API ์„œ๋ฒ„๋กœ kubernetes ์›Œํฌ๋กœ๋“œ ์šฉ์–ด Daemon set Deployment Job Pod Replica set Replication controller
new 08_connect_DB
๐Ÿƒ Spring
DataSource ์„ค์ • AppCtx.java 1 @Bean(destroyMethod = "close") 2 public DataSource dataSource() { 3 DataSource ds = new DataSource(); 4 ds.setDriverClassName("com.mysql.jdbc.Driver"); 5 ds.setUrl("jdbc:mysql://localhost/spring5fs?"+ 6 "enabledTLSProtocols=TLSv1.2&"+ 7 "useSSL=false&"+ 8 "characterEncoding=utf8"); 9 ds.setUsername("spring5"); 10 ds.setPassword("spring5"); 11 ds.setInitialSize(2); 12 ds.setMaxActive(10); 13 ds.setTestWhileIdle(true); 14 ds.setMinEvictableIdleTimeMillis(60000 * 3); 15 ds.setTimeBetweenEvictionRunsMillis(10 * 1000); 16 return ds; 17 } Query ์‹คํ–‰ JdbcTemplate์„ ์ด์šฉํ•œ select 1jdbcTemplate.query( 2"select * from MEMBER where EMAIL = ?", 3new RowMapper<Member>() { 4 @Override 5 public Member mapRow(ResultSet rs, int rowNum) 6 throws SQLException { 7 Member member = new Member( 8 rs.getString("EMAIL"), 9 rs.getString("PASSWORD"), 10 rs.getString("NAME"), 11 rs.getTimestamp("REGDATE").toLocalDateTime()); 12 member.setId(rs.getLong("ID")); 13 return member; 14 } 15 }, 16 email); PreparedStatementCreater๋ฅผ ์ด์šฉํ•œ update 1jdbcTemplate.update(new PreparedStatementCreator() { 2 @Override 3 public PreparedStatement createPreparedStatement(Connection con) 4 throws SQLException { 5 PreparedStatement pstmt = con.prepareStatement( 6 "insert into MEMBER (EMAIL, PASSWORD, NAME, REGDATE) values (?, ?, ?, ?)"); 7 pstmt.setString(1, member.getEmail()); 8 pstmt.setString(2, member.getPassword()); 9 pstmt.setString(3, member.getName()); 10 pstmt.setTimestamp(4, Timestamp.valueOf(member.getRegisterDateTime())); 11 12 return pstmt; 13 } 14}) java.sql.SQLException: Unable to load class: come.mysql.jdbc.Driver from … ์˜ค๋ฅ˜๋ฅผ ์ž˜ ๋ณด์ž… come.mysql… ์˜คํƒ€๋กœ ์ธํ•œ ๋ฌธ์ œ์˜€๋‹ค java.sql.SQLException: Unable to load authentication plugin ‘caching_sha2_password’. mysql ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ ๋ฐฉ์‹์— ๋”ฐ๋ฅธ ์˜ค๋ฅ˜์ด๋‹ค ํ•ด๊ฒฐ๋ฐฉ๋ฒ• : mysql์—์„œ ๋น„๋ฐ€๋ฒˆํ˜ธ ์ธ์ฆ๋ฐฉ์‹์„ ๋ฐ”๊พธ์ž 1ALTER USER '์‚ฌ์šฉ์ž'@'localhost' IDENTIFIED WITH mysql_native_password BY '๋น„๋ฐ€๋ฒˆํ˜ธ'; javax.net.ssl.SSLHandshakeException: No appropriate protocol (protocol is disabled or cipher suites are inappropriate) url์— enabledTLSProtocols=TLSv1.2๋ฅผ ์ง€์ •ํ•˜์—ฌ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ๋‹ค urlํ˜•์‹๋•Œ๋ฌธ์— ํ•ด๊ฒฐํ•˜๋Š”๋ฐ ์กฐ๊ธˆ ์‹œ๊ฐ„์ด ๊ฑธ๋ ธ๋‹ค. ์˜ฌ๋ฐ”๋ฅธ URL ํ˜•์‹์€ ์•„๋ž˜์™€ ๊ฐ™๋‹ค ๊ธฐ์–ตํ•˜์ž jdbc:mysql://localhost/spring5fs?์†์„ฑ1=๊ฐ’1&์†์„ฑ2=๊ฐ’2…" Transaction ์ฒ˜๋ฆฌ Transaction ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์˜ ์ƒํƒœ๋ฅผ ๋ณ€ํ™”์‹œํ‚ค๊ธฐ ์œ„ํ•ด ์ˆ˜ํ–‰ํ•˜๋Š” ์ž‘์—…์˜ ๋‹จ์œ„ ๋ฐฐ๊ฒฝ ์ฟผ๋ฆฌ ๋‘ ๊ฐœ๋ฅผ ์‹คํ–‰ํ•˜๋Š”๋ฐ ๋งŒ์•ฝ 2๋ฒˆ์งธ ์ฟผ๋ฆฌ์—์„œ ์˜ค๋ฅ˜๊ฐ€ ๋ฐœ์ƒํ–ˆ์„๋•Œ 1๋ฒˆ์งธ ์ฟผ๋ฆฌ ์‹คํ–‰ ์ด์ „ ์ƒํƒœ๋กœ ๋˜๋Œ๋ฆฌ๋Š” (๋กค๋ฐฑ) ์ž‘์—…์ด ํ•„์š”ํ•˜๋‹ค ์ด์™€ ๊ฐ™์ด ์ฟผ๋ฆฌ ๋‘ ๊ฐœ๋ฅผ ๋ฌถ์–ด์•ผ ํ•˜๋Š” ์ƒํ™ฉ์— Transaction์„ ์ด์šฉํ•œ๋‹ค. rollback ํ•จ์ˆ˜๋ฅผ ์ง์ ‘ ํ˜ธ์ถœํ•˜๋Š” ๋ฐฉ๋ฒ•๋„ ์žˆ์ง€๋งŒ, Spring์—์„œ๋Š” @Transactional์„ ์ด์šฉํ•ด ๋” ๊ฐ„ํŽธํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. AppCtx.java 1@Bean 2public PlatformTransactionManager transactionManager() { 3 DataSourceTransactionManager tm = new DataSourceTransactionManager(); 4 tm.setDataSource(dataSource()); 5 return tm; 6} ChangePasswordService.java 1@Transactional 2public void changePassword(String email, String oldPwd, String newPwd) { 3 Member member = memberDao.selectByEmail(email); 4 5 if (member == null) 6 throw new MemberNotFoundException(); 7 8 member.changePassword(oldPwd, newPwd); 9 memberDao.update(member); 10} ํŠธ๋žœ์žญ์…˜ ๊ด€๋ จ ๋กœ๊ทธ ๋ฉ”์‹œ์ง€ ์ถœ๋ ฅ logback.xml 1<?xml version="1.0" encoding="UTF-8"> 2 3<configuration> 4 <appender name="stdout" class="chqos.logback.core.ConsoleAppender"> 5 <encoder> 6 <pattern>%d %5p %c{2} - %m%n</pattern> 7 </encoder> 8 </appender> 9 <root level="INFO"> 10 <appender-ref ref="stdout" /> 11 </root> 12 13 <logger name="org.springframework.jdbc" level="DEBUG" /> 14</configuration> ๋กœ๊ทธ ์ถœ๋ ฅํ•˜๋Š” ๊ฒƒ๋„ ๋ฐฐ์›Œ๋ณด์•˜๋‹ค. Transaction ์ „ํŒŒ 1public class SomeService { 2 private AnyService anyService; 3 4 @Transactional 5 public void some() { 6 anyService.any(); 7 } 8 9 public void setAnyService(AnyService as) { 10 anyService = as; 11 } 12} 13 14public class AnyService { 15 @Transactional 16 public void any() { ... } 17} some๋ฉ”์†Œ๋“œ๊ฐ€ any๋ฉ”์†Œ๋“œ๋ฅผ ํ˜ธ์ถœํ–ˆ๋‹ค. ์œ„ ์ฝ”๋“œ์—์„œ๋Š” ๋ฉ”์†Œ๋“œ ๋‘˜ ๋‹ค @Transactional์ด ๋ถ™์–ด์žˆ์ง€๋งŒ ๋งŒ์•ฝ ๋ถ™์–ด์žˆ์ง€ ์•Š์œผ๋ฉด ์–ด๋–ป๊ฒŒ ๋ ๊นŒ? ์ด๋ ‡๊ฒŒ ๋ฉ”์†Œ๋“œ ๊ฐ„ ํ˜ธ์ถœ์ด ๋ฐœ์ƒํ•  ๋•Œ ํŠธ๋žœ์žญ์…˜์ด ์œ ์ง€๋˜๋Š” ๊ฒƒ์„ ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒ๋ผ๊ณ  ํ•œ๋‹ค. @Transactional annotation์— ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ์†์„ฑ ์ค‘ propagation์ด ํŠธ๋žœ์žญ์…˜ ์ „ํŒŒํƒ€์ž…์„ ์ง€์ •ํ•œ๋‹ค. ๊ธฐ๋ณธ๊ฐ’ : REQUIRED : ํ˜„์žฌ ์ง„ํ–‰์ค‘์ธ ํŠธ๋žœ์žญ์…˜์ด ์กด์žฌํ•˜๋ฉด ํ•ด๋‹น ํŠธ๋žœ์žญ์…˜ ์‚ฌ์šฉ, ์กด์žฌํ•˜์ง€ ์•Š์œผ๋ฉด ์ƒˆ๋กœ์šด ํŠธ๋žœ์žญ์…˜์„ ์ƒ์„ฑํ•œ๋‹ค
new 09_spring_MVC
๐Ÿƒ Spring
Spring MVC ์‹œ์ž‘ํ•˜๊ธฐ ํ”„๋กœ์ ํŠธ ์ƒ์„ฑ ์•ž์—์„œ ๋งŒ๋“ค์—ˆ๋˜ ์ž๋ฐ” ์• ํ”Œ๋ฆฌ์ผ€์ด์…˜๊ณผ๋Š” ์ข€ ๋‹ค๋ฅธ์ ์ด ์žˆ์—ˆ๋‹ค jar์ด ์•„๋‹Œ war์„ ์‚ฌ์šฉํ•˜๋Š” ๋“ฑ ์—ฌ๋Ÿฌ๊ฐ€์ง€ ๋งŽ์•˜๋Š”๋ฐ ์ผ์ผ์ด ์ ์ง€๋Š” ์•Š์„ ๊ฒƒ์ด๋‹ค Controller 1@Controller 2public class HelloController { 3 @GetMapping("/hello") 4 public String hello(Model model, 5 @RequestParam(value="name", required=false) String name) { 6 model.addAttribute("greeting", "์•ˆ๋…•ํ•˜์„ธ์š”" + name); 7 return "hello"; 8 } 9} JSP 1<%@ page contentType="text/html; charset=utf-8" %> 2<!DOCTYPE html> 3<html> 4 <head> 5 <title>Hello</title> 6 </head> 7 <body> 8 ์ธ์‚ฌ๋ง : ${greeting} 9 </body> 10</html URL์ ‘์†ํ•ด๋„ ํ•ด๋‹น jspํŒŒ์ผ์ด ๋‚˜์˜ค์ง€ ์•Š๋Š” ๋ฌธ์ œ vscode์—์„œ community server connector๋ผ๋Š” extension์„ ํ†ตํ•ด tomcat์„ ๋„์›Œ์„œ ํ• ๋ ค๊ณ  ํ•œ๋‹ค ํŠน์ • jsp๋ฅผ ๊ฐ์ง€ํ–ˆ๋Š”์ง€, servingํ•˜๋Š”์ง€์— ๋Œ€ํ•œ ๋กœ๊ทธ๊ฐ€ ์—†์–ด ๋˜๋Š”๊ฑด์ง€ ์•Œ ์ˆ˜๊ฐ€ ์—†๋‹ค web.xml; lineNumber: 1; columnNumber: 37; A pseudo attribute name is expected. // before <?xml version="1.0" encoding="UTF-8"> // after <?xml version="1.0" encoding="UTF-8"?> ๋ฌผ์Œํ‘œ๋ฅผ ๋นผ๋จน์–ด์„œ ์ƒ๊ธฐ๋Š” ์˜ค๋ฅ˜์ด๋‹ค 404: Not Found 1// before 2registry.jsp("/WEB-INF/view", ".jsp"); 3// after 4registry.jsp("/WEB-INF/view/", ".jsp");
new Spring ๊ฐœ๋… - Bean Lifecycle & Scope
๐Ÿƒ Spring
Bean ๊ฐ์ฒด์˜ Lifecycle Bean ๊ฐ์ฒด๊ฐ€ ์ƒ์„ฑ ๋˜๋Š” ์†Œ๋ฉธ๋ ๋•Œ ํŠน์ • ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•˜๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. @PostConstruct, @PreDestroy Annotation ์‚ฌ์šฉ 1// Bean ๊ฐ์ฒด ์ƒ์„ฑ๋  ๋•Œ ์‹คํ–‰ 2@PostConstruct 3public void postConstruct() {...} 4 5// Bean ๊ฐ์ฒด ์†Œ๋ฉธ๋  ๋•Œ ์‹คํ–‰ 6@PreDestroy 7public void preDestroy() {...} InitializingBean, DisposableBean ๊ตฌํ˜„ 1public class Client implements InitializingBean, DisposableBean { 2 // Bean ๊ฐ์ฒด ์ƒ์„ฑ๋  ๋•Œ ์‹คํ–‰ 3 @Override 4 public void afterPropertiesSet() throws Exception {...} 5 6 // Bean ๊ฐ์ฒด ์†Œ๋ฉธ๋  ๋•Œ ์‹คํ–‰ 7 @Override 8 public void destroy() throws Exception {...} 9} @Bean Annotation์—์„œ ์„ค์ • 1@Bean(initMethod = "init", destroyMethod="close") 2public class Client2{ 3 // Bean ๊ฐ์ฒด ์ƒ์„ฑ๋  ๋•Œ ์‹คํ–‰ 4 public void init() {...} 5 // Bean ๊ฐ์ฒด ์†Œ๋ฉธ๋  ๋•Œ ์‹คํ–‰ 6 public void close() {...} 7} Bean ๊ฐ์ฒด์˜ Scope ๊ธฐ๋ณธ์ ์œผ๋กœ Bean ๊ฐ์ฒด๋Š” Singleton scope๋ฅผ ๊ฐ–๋Š”๋‹ค ํ•˜์ง€๋งŒ ์ž„์˜๋กœ Prototype scope๋ฅผ ๊ฐ–๊ฒŒ ํ•  ์ˆ˜ ์žˆ๋‹ค. 1@Configuration 2public class AppCtx { 3 @Bean 4 @Scope("prototype") 5 public Client client() {} 6}
new Spring - Bean Validation : Annotation์œผ๋กœ Validationํ•˜๊ธฐ
๐Ÿƒ Spring
Bean Validation Annotation์„ ๋‹ฌ์•„์„œ Validation์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค. ์ฃผ๋กœ jakarta.validation๊ณผ hibernate.validator ๋‘ ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•œ๋‹ค. Dependency Diagram ๊ตฌ์กฐ spring-boot-starter-validation -> hibernate-validator -> jakarta.validation-api jakarta.validation์—์„œ ์ง€์›ํ•˜๋Š” annotation Annotation Description @NotNull null์ด ์•„๋‹Œ๊ฐ€ ("", " " => ํ†ต๊ณผ) @NotEmpty null์ด ์•„๋‹ˆ๊ณ , size๊ฐ€ 0์ธ๊ฐ€ (" " => ํ†ต๊ณผ) @NotBlank null์ด ์•„๋‹ˆ๊ณ , trimํ•œ ๊ฒฐ๊ณผ๊ฐ€ empty์ธ๊ฐ€ @Size ๋ฌธ์ž์—ด, ๋ฐฐ์—ด์˜ ๊ธธ์ด๊ฐ€ ํ•ด๋‹น ๋ฒ”์œ„์— ์žˆ๋Š”๊ฐ€ @Min ์ˆซ์ž๊ฐ€ ํ•ด๋‹น ๋ฒ”์œ„์— ์žˆ๋Š”๊ฐ€ @Max ์ˆซ์ž๊ฐ€ ํ•ด๋‹น ๋ฒ”์œ„์— ์žˆ๋Š”๊ฐ€ @Email ์ด๋ฉ”์ผ ํ˜•์‹์— ๋งž๋Š”๊ฐ€ @Pattern Regex(์ •๊ทœ์‹)์— ๋งž๋Š”๊ฐ€ @Past ๊ณผ๊ฑฐ์˜ ๋‚ ์งœ์ธ๊ฐ€ @Future ๋ฏธ๋ž˜์˜ ๋‚ ์งœ์ธ๊ฐ€ @Digits ์ •์ˆ˜, ์†Œ์ˆ˜ ์ž๋ฆฟ์ˆ˜๊ฐ€ ํ•ด๋‹น ๋ฒ”์œ„์— ์žˆ๋Š”๊ฐ€ @DecimalMin, @DecimalMax ์ž๋ฆฟ์ˆ˜๊ฐ€ ํ•ด๋‹น ๋ฒ”์œ„์— ์žˆ๋Š”๊ฐ€ (์†Œ์ˆ˜ ์ดํ•˜ ์ž๋ฆฟ์ˆ˜ ํฌํ•จ) @Positive, @PositiveOrZero, @Negative, @NegativeOrZero hibernate.validator์—์„œ ์ง€์›ํ•˜๋Š” annotation Annotation Description @Range ์ˆซ์ž๊ฐ€ ํ•ด๋‹น ๋ฒ”์œ„์— ์žˆ๋Š”๊ฐ€ (์†Œ์ˆ˜ ์ดํ•˜ ์ž๋ฆฟ์ˆ˜ ํฌํ•จ) @Length ๋ฌธ์ž์—ด, ๋ฐฐ์—ด์˜ ๊ธธ์ด๊ฐ€ ํ•ด๋‹น ๋ฒ”์œ„์— ์žˆ๋Š”๊ฐ€ @URL URL ํ˜•์‹์— ๋งž๋Š”๊ฐ€ ์–ธ๊ธ‰ํ•œ Annotation๋ง๊ณ  ๋‹ค๋ฅธ Annotation๋„ ์žˆ๋‹ค. Rest Controller์—์„œ ์‚ฌ์šฉ Controller 1public ResponseEntity<Customer> postCustomer(@RequestBody @Valid CustomerDTO customerDTO) {...} @Valid Annotation์„ ๋ถ™์—ฌ์„œ CustomerDTO ๊ฐ์ฒด์— ๋Œ€ํ•œ Validation์„ ์ˆ˜ํ–‰ํ•œ๋‹ค @Valid Annotation์„ ๋ถ™์ด๋Š” ๊ฒƒ์„ ๊นœ๋นกํ•˜์ง€ ๋ง์ž ์˜ˆ์™ธ ์ฒ˜๋ฆฌ ์œ„ ์ฝ”๋“œ์˜ Validation์—์„œ ์‹คํŒจํ•˜๋ฉด, MethodArgumentNotValidException์ด ๋ฐœ์ƒํ•œ๋‹ค ํ•ด๋‹น ์˜ˆ์™ธ๋Š” ํ•„๋“œ๋ณ„ ๋ชจ๋“  ์—๋Ÿฌ๋ฅผ ๋‹ด๊ณ  ์žˆ๋‹ค ๊ทธ๋Œ€๋กœ ๋ฐ˜ํ™˜ํ•˜๋ฉด ์—„์ฒญ ๊ธธ๊ธฐ ๋•Œ๋ฌธ์—, ๋ณดํ†ต ์•„๋ž˜ ์ฝ”๋“œ์™€ ๊ฐ™์ด ํ•„์š”ํ•œ ์ •๋ณด๋งŒ ์ถ”์ถœํ•ด์„œ ๋ฐ˜ํ™˜ํ•œ๋‹ค 1processValidationErrors(MethodArgumentNotValidException e) { 2 List<String> errors = e.getBindingResult().getFieldErrors().stream() 3 .map(error -> error.getField() + ": " + error.getDefaultMessage()) 4 .collect(Collectors.toList()); 5 return new ResponseEntity<>(errors, HttpStatus.BAD_REQUEST); 6} ์ˆ˜๋™ Validation Controller์—์„œ Validation์„ ์ˆ˜ํ–‰ํ•˜์ง€ ๋ชปํ•˜๋Š” ๊ฒฝ์šฐ, ์ˆ˜๋™์œผ๋กœ Validation์„ ์ˆ˜ํ–‰ํ•  ์ˆ˜ ์žˆ๋‹ค ์ด๋•Œ, Validator ๊ฐ์ฒด๋ฅผ ์ฃผ์ž…๋ฐ›์•„์„œ ์‚ฌ์šฉํ•œ๋‹ค 1import jakarta.validation.Validator; 2... 3@Autowired 4private Validator validator; 5... 6var violations = validator.validate(voucher); 7if (!violations.isEmpty()) 8 throw new IllegalArgumentException(violations.stream().findFirst().get().getMessage()); ์ฝ”๋“œ์—์„œ๋Š” voucher ๊ฐ์ฒด์— ๋Œ€ํ•œ Validation์„ ์ˆ˜ํ–‰ํ•˜๊ณ , ๋ฐœ์ƒํ•œ ์—๋Ÿฌ๊ฐ€ ์žˆ๋‹ค๋ฉด IllegalArgumentException์„ ๋ฐœ์ƒ์‹œํ‚จ๋‹ค
new ๋ฐฑ์ค€ - 2502 : ๋–ก ๋จน๋Š” ํ˜ธ๋ž‘์ด (S1)
๐Ÿง  Algorithm
1D, K = map(int, input().split()) 2L = [(1, 0), (0, 1)] 3 4for i in range(2, D): 5 L.append((L[i-2][0]+L[i-1][0], L[i-2][1]+L[i-1][1])) 6 7A = 1 8B = 2 9 10while True: 11 if A*L[D-1][0] + B*L[D-1][1] == K: 12 break 13 14 if A+1 == B: 15 B += 1 16 A = 1 17 else: 18 A += 1 19 20print (A,'\n',B, sep='') ํ•ด๊ฒฐ๋ฐฉ๋ฒ• N๋ฒˆ์งธ๋‚  ๋–ก ๊ฐœ์ˆ˜๋ฅผ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด ์ฒซ์งธ๋‚  ๋–ก, ๋‘˜์งธ๋‚  ๋–ก์„ ๊ฐ๊ฐ ๋ช‡๋ฒˆ ๋”ํ•ด์•ผํ•˜๋Š”์ง€ ๋ฆฌ์ŠคํŠธ์— ๊ตฌํ•œ๋‹ค ์ฒซ์งธ, ๋‘˜์งธ ๋‚  ๋–ก์„ ํ•˜๋‚˜ํ•˜๋‚˜ ๋„ฃ์–ด๋ณด๋ฉด์„œ ๋ธŒ๋ฃจํŠธ ํฌ์Šค๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค
new ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค - ์ˆซ์ž ์นด๋“œ ๋‚˜๋ˆ„๊ธฐ (L2)
๐Ÿง  Algorithm
์ฒซ๋ฒˆ์งธ ํ†ต๊ณผํ•œ ํ’€์ด 1import math 2 3def gcd(a, b): 4 while b > 0: 5 a, b = b, a%b 6 return a 7 8def gcdOfArr(l): 9 result = l[0] 10 for i in range(1, len(l)): 11 result = gcd(result, l[i]) 12 return result 13 14def solution(arrayA, arrayB): 15 a1 = gcdOfArr(arrayA) 16 for i in arrayB: 17 if i % a1 == 0: 18 a1 = 0 19 break 20 a2 = gcdOfArr(arrayB) 21 for i in arrayA: 22 if i % a2 == 0: 23 a2 = 0 24 break 25 return max(a1, a2) ๊ฐœ์„ ํ•œ ํ’€์ด 1import math 2from functools import reduce 3 4def gcd(a, b): 5 while b > 0: 6 a, b = b, a%b 7 return a 8 9def solution(arrayA, arrayB): 10 a1 = reduce(gcd, arrayA) 11 a1 = 0 if any(i % a1 == 0 for i in arrayB) else a1 12 a2 = reduce(gcd, arrayB) 13 a2 = 0 if any(i % a2 == 0 for i in arrayA) else a2 14 return max(a1, a2) ๋ฌธ์ œ ์ฒ ์ˆ˜๊ฐ€ ๊ฐ€์ง„ ์ˆซ์ž์˜ ๋ฐฐ์—ด arrayA, ์˜ํฌ๊ฐ€ ๊ฐ€์ง„ ์ˆซ์ž์˜ ๋ฐฐ์—ด arrayB๊ฐ€ ์ฃผ์–ด์ง„๋‹ค ์ฒ ์ˆ˜๊ฐ€ ๊ฐ€์ง„ ์นด๋“œ๋“ค์˜ ๋ชจ๋“  ์ˆซ์ž๋ฅผ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๊ณ , ์˜ํฌ๊ฐ€ ๊ฐ€์ง„ ์ˆซ์ž๋Š” ํ•˜๋‚˜๋„ ๋‚˜๋ˆŒ ์ˆ˜ ์—†๋Š” ์–‘์˜ ์ •์ˆ˜ a ์˜ํฌ๊ฐ€ ๊ฐ€์ง„ ์นด๋“œ๋“ค์˜ ๋ชจ๋“  ์ˆซ์ž๋ฅผ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ๊ณ , ์ฒ ์ˆ˜๊ฐ€ ๊ฐ€์ง„ ์ˆซ์ž๋Š” ํ•˜๋‚˜๋„ ๋‚˜๋ˆŒ ์ˆ˜ ์—†๋Š” ์–‘์˜ ์ •์ˆ˜ a ๊ฐ€์žฅ ํฐ ์–‘์˜ ์ •์ˆ˜ a๋ฅผ ๊ตฌํ•˜๋ผ, ์—†๋‹ค๋ฉด 0์„ ๋ฐ˜ํ™˜ํ•˜๋ผ TC input [14, 35, 119] ouput 7 ํ•ด๊ฒฐ๋ฐฉ๋ฒ• ํ”„๋กœ๊ทธ๋ž˜๋จธ์Šค์—์„œ ์ง€์›ํ•˜๋Š” ํŒŒ์ด์ฌ์ด 3.8์ด๋ผ์„œ ๋‚ด์žฅํ•จ์ˆ˜ math.gcd(3.9๋ถ€ํ„ฐ ์ง€์›)๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ๋ชปํ–ˆ๋‹ค ์œ ํด๋ฆฌ๋“œ ํ˜ธ์ œ๋ฒ• ๊ธฐ์–ต์ด ๋‚˜์ง€ ์•Š์•„์„œ ์•ฝ๊ฐ„์˜ ๊ตฌ๊ธ€๋ง์„ ํ†ตํ•ด ํ•ด๊ฒฐํ•˜์˜€๋‹ค reduce์™€ anyํ•จ์ˆ˜๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ์˜ ๊ธธ์ด๋ฅผ ๋Œ€ํญ ๊ฐ์†Œ ์‹œํ‚ฌ ์ˆ˜ ์žˆ์—ˆ๋‹ค, ์ž์ฃผ ํ™œ์šฉํ•˜์ž
new Express&React ํ”„๋กœ์ ํŠธ์— Recaptcha v3 ์ ์šฉํ•˜๊ธฐ
๐ŸŒ Javascript
์ƒํ™ฉ ์‚ฌ์ด๋“œ ํ”„๋กœ์ ํŠธ “์•Œ๋ก"์„ ๊ฐœ๋ฐœํ•˜๋˜ ์ค‘, ์‚ฌ์šฉ์ž๊ฐ€ ์•…์˜์ ์ธ ๋ชฉ์ ์œผ๋กœ ๋ฐ˜๋ณต์ ์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ฒƒ์„ ์–ด๋–ป๊ฒŒ ๋ง‰์„๊นŒ ๊ณ ๋ฏผํ•˜๊ฒŒ ๋˜์—ˆ๋‹ค. ์กฐ์‚ฌ๋ฅผ ํ†ตํ•ด Google์—์„œ ์ œ๊ณต๋˜๋Š” Recaptcha๋ฅผ ์‚ฌ์šฉํ•˜๋ฉด ์†์‰ฝ๊ฒŒ ๋ฐฉ์ง€ํ•  ์ˆ˜ ์žˆ๋‹ค๋Š” ๊ฒƒ์„ ์•Œ๊ฒŒ ๋˜์—ˆ๋‹ค. ๊ณต๊ฒฉ์ž์˜ ์ž…์žฅ์—์„œ ์ƒ๊ฐํ–ˆ์„ ๋•Œ, ์ง€๊ธˆ ํ”„๋กœ์ ํŠธ์—์„œ ๊ฐ€์žฅ ์ทจ์•ฝํ•œ ๋ถ€๋ถ„์€ ํšŒ์›๊ฐ€์ž…์ด๋ผ๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ํšŒ์›๊ฐ€์ž…์€ ํšŒ์›์ด ์•„๋‹Œ ์ž๊ฐ€, ์•„์ด๋””์™€ ๋น„๋ฐ€๋ฒˆํ˜ธ ๊ทœ์น™๋งŒ ๋งŒ์กฑํ•œ๋‹ค๋ฉด ๋ฐ˜๋ณต์ ์œผ๋กœ ์š”์ฒญ์„ ๋ณด๋‚ผ ์ˆ˜ ์žˆ๊ณ , ์ด๋Š” DB์— ๋ฐ”๋กœ ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ๋”ฐ๋ผ์„œ ํšŒ์›๊ฐ€์ž… ๋ถ€๋ถ„์— Recaptcha๋ฅผ ์ ์šฉํ•˜๊ธฐ๋กœ ๊ฒฐ์ •ํ–ˆ๋‹ค. Recaptcha๋ž€? Recaptcha๋Š” ๊ตฌ๊ธ€์—์„œ ์ œ๊ณตํ•˜๋Š” ๋ฌด๋ฃŒ ๋ณด์•ˆ ์„œ๋น„์Šค๋กœ, ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๋ด‡์ด ์•„๋‹˜์„ ์ฆ๋ช…ํ•˜๋Š” ๋ฐฉ๋ฒ• ์ค‘ ํ•˜๋‚˜์ด๋‹ค. ์ง€์› ์ข…๋ฃŒ๋œ v1์„ ์ œ์™ธํ•˜๋ฉด v2, v3 ๋‘ ๊ฐ€์ง€ ๋ฒ„์ „์ด ์žˆ๋‹ค. v2๋Š” ์‚ฌ์šฉ์ž๊ฐ€ ‘๋‚˜๋Š” ๋กœ๋ด‡์ด ์•„๋‹™๋‹ˆ๋‹ค’๋ฅผ ํด๋ฆญํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ ์ธ์ฆ์ด ์™„๋ฃŒ๋œ๋‹ค. v3๋Š” ์‚ฌ์šฉ์ž์™€ ์ƒํ˜ธ์ž‘์šฉ ์—†์ด ์ž๋™์œผ๋กœ ์ธ์ฆ์ด ์™„๋ฃŒ๋œ๋‹ค. ํ•„์ž๋Š” ์‚ฌ์šฉ์ž์˜ ๊ฒฝํ—˜๊ณผ ์ด๋ฅผ ํ…Œ์ŠคํŠธํ•  ๋‚˜์˜ ๊ณ ์ƒ์„ ๋œ๊ธฐ ์œ„ํ•ด v3๋ฅผ ์‚ฌ์šฉํ•˜๊ธฐ๋กœ ํ–ˆ๋‹ค. v3์˜ ์ž‘๋™ ๋ฐฉ์‹ ์‚ฌ์šฉ์ž์˜ ๋งˆ์šฐ์Šค ํด๋ฆญ, ํ‚ค๋ณด๋“œ ์ž…๋ ฅ, ์Šคํฌ๋กค, ์š”์ฒญ ํŒจํ„ด ๋“ฑ์„ ๋ถ„์„ํ•˜์—ฌ ์ ์ˆ˜๋ฅผ ๋งค๊ธด๋‹ค. ์ ์ˆ˜๋Š” 0.0 ~ 1.0 ์‚ฌ์ด์˜ ๊ฐ’์œผ๋กœ, 0.0์€ ๋กœ๋ด‡, 1.0์€ ์‚ฌ๋žŒ์„ ์˜๋ฏธํ•œ๋‹ค. ๊ฐœ๋ฐœ์ž๋Š” Recaptcha๊ฐ€ ํ‰๊ฐ€ํ•œ ์ ์ˆ˜๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ์š”์ฒญ์„ ๋ฐ›์•„๋“ค์ผ์ง€ ๋ง์ง€ ๊ฒฐ์ •ํ•  ์ˆ˜ ์žˆ๋‹ค. ์˜ˆ์ƒ ์‹œ๋‚˜๋ฆฌ์˜ค ์‚ฌ์šฉ์ž๊ฐ€ ํšŒ์›๊ฐ€์ž… ํŽ˜์ด์ง€์— ์ ‘์†ํ•œ๋‹ค. ๋ธŒ๋ผ์šฐ์ €๋‹จ์—์„œ Recaptcha ํ‚ค๋ฅผ Recaptcha ํ† ํฐ์„ ๋ฐ›์•„์˜จ๋‹ค. ์‚ฌ์šฉ์ž๊ฐ€ ํšŒ์›๊ฐ€์ž… ์š”์ฒญ์„ ๋ณด๋‚ผ ๋•Œ, Recaptcha ํ† ํฐ์„ ํ•จ๊ป˜ ์ „๋‹ฌํ•œ๋‹ค. ์„œ๋ฒ„์—์„œ Recaptcha ํ† ํฐ์„ ๊ฒ€์ฆํ•˜๊ณ , ์ ์ˆ˜๊ฐ€ 0.5๋ณด๋‹ค ๋‚ฎ์œผ๋ฉด ์š”์ฒญ์„ ๊ฑฐ๋ถ€ํ•œ๋‹ค. ์ ์šฉ ์‚ฌ์ „ ์„ค์ • https://www.google.com/recaptcha/์— ์ ‘์†ํ•˜์—ฌ ๋„๋ฉ”์ธ์„ ๋“ฑ๋กํ•˜๊ณ  ํ‚ค๋ฅผ ๋ฐ›๋Š”๋‹ค. ์ž์„ธํ•œ ๊ณผ์ •์€ ๋‹ค๋ฅธ ๋ธ”๋กœ๊ทธ์—๋„ ์ž˜ ์„ค๋ช…๋˜์–ด ์žˆ์–ด์„œ ์ƒ๋žตํ•œ๋‹ค. Server (Express) user-service.ts 1// ์„œ๋น„์Šค ๋ ˆ์ด์–ด์— ์ถ”๊ฐ€ํ•œ Recaptcha ๊ฒ€์ฆ ํ•จ์ˆ˜ 2static async verifyRecaptcha(token: string): Promise<void> { 3 // Recaptcha ๊ฒ€์ฆ 4 const response = await fetch( 5 // ํ‚ค๋Š” Recaptcha ์‚ฌ์ดํŠธ์—์„œ ๋ฐ›์€ ๊ฒƒ์ด๋ฉฐ, ํ™˜๊ฒฝ ๋ณ€์ˆ˜๋กœ ๊ด€๋ฆฌ 6 `https://www.google.com/recaptcha/api/siteverify?secret=${process.env.RECAPTCHA_SECRET_KEY}&response=${token}`, 7 { 8 method: "POST", 9 } 10 ); 11 // ๊ฒฐ๊ณผ๋ฅผ JSON์œผ๋กœ ํŒŒ์‹ฑ 12 const verificationReuslt = await response.json(); 13 14 // ์ ์ˆ˜๊ฐ€ 0.5๋ณด๋‹ค ๋‚ฎ์œผ๋ฉด ์˜ˆ์™ธ๋ฅผ ๋˜์ง 15 if (verificationReuslt.score <= 0.5) { 16 throw new RecaptchaScoreTooLowError(); 17 } 18 19 // ์„ฑ๊ณต ์—ฌ๋ถ€๊ฐ€ false์ด๋ฉด ์˜ˆ์™ธ๋ฅผ ๋˜์ง (ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ) 20 if (!verificationReuslt.success) { 21 throw new RecaptchaTokenInvalidError(); 22 } 23} user-router.ts 1// ์ปจํŠธ๋กค๋Ÿฌ ๋ถ€๋ถ„์—์„œ ๋ถ€๋ถ„์—์„œ Recaptcha ๊ฒ€์ฆ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœ, ๋ฐœ์ƒ์‹œํ‚จ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌ 2try { 3 await UserService.verifyRecaptcha(recaptchaToken); 4 await UserService.createUser(username, password); 5 res.status(201).send("User created successfully"); 6} catch (err: any) { 7 // Recaptcha ์ ์ˆ˜๊ฐ€ ๋‚ฎ์€ ๊ฒฝ์šฐ -> 403 Forbidden 8 if (err instanceof RecaptchaScoreTooLowError) { 9 res.status(403).send(err.message); 10 // Recaptcha ํ† ํฐ์ด ์œ ํšจํ•˜์ง€ ์•Š์€ ๊ฒฝ์šฐ -> 400 Bad Request 11 } else if (err instanceof RecaptchaTokenInvalidError) { 12 res.status(400).send(err.message); 13 } else if (err instanceof UserAlreadyExistsError) { 14 res.status(409).send(err.message); 15 } else { 16 console.error(err); 17 res.status(500).send(err.message); 18 } 19} Client (React) App.tsx 1import { GoogleReCaptchaProvider } from "react-google-recaptcha-v3"; 2 3return ( 4 // ์ตœ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์— GoogleReCaptchaProvider๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ Recaptcha ํ‚ค๋ฅผ ์ „๋‹ฌ 5 <GoogleReCaptchaProvider 6 reCaptchaKey={process.env.REACT_APP_RECAPTCHA_SITE_KEY || ""} 7 > 8 <Router> 9 {/* ... */} 10 </Router> 11 </GoogleReCaptchaProvider> 12); SignupPage.tsx 1import { useGoogleReCaptcha } from "react-google-recaptcha-v3"; 2 3const SignupPage: React.FC = () => { 4 // useGoogleReCaptcha ํ›…์„ ์‚ฌ์šฉํ•˜์—ฌ Recaptcha ํ† ํฐ์„ ๋ฐ›์•„์˜ด 5 const { executeRecaptcha } = useGoogleReCaptcha(); 6 7 const handleSignup = async () => { 8 // Recaptcha ํ† ํฐ์„ ๋ฐ›์•„์˜ค๊ธฐ๋„ ์ „์— ์‚ฌ์šฉ์ž๊ฐ€ ํšŒ์›๊ฐ€์ž…์„ ์‹œ๋„ํ•˜๋Š” ๊ฒฝ์šฐ 9 if (!executeRecaptcha) { 10 console.log("Execute recaptcha not yet available"); 11 return; 12 } 13 // Recaptcha ํ† ํฐ์„ ๋ฐ›์•„์˜ด (signup์€ action์„ ๊ตฌ๋ถ„ํ•˜๊ธฐ ์œ„ํ•œ ๋ฌธ์ž์—ด) 14 const recaptchaToken = await executeRecaptcha("signup"); 15 16 if (password !== confirmPassword) { 17 alert("๋น„๋ฐ€๋ฒˆํ˜ธ๊ฐ€ ์ผ์น˜ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค."); 18 return; 19 } 20 21 try { 22 const response = await api.post<SignupResponse>("/users/signup", { 23 username, 24 password, 25 // ์„œ๋ฒ„๋กœ Recaptcha ํ† ํฐ์„ ์ „๋‹ฌ 26 recaptchaToken, 27 }); 28 } catch() { 29 // ... 30 } 31 }; 32}; ๊ฒฐ๊ณผ ๊ด€๋ฆฌ์ž ์ฝ˜์†”์„ ํ†ตํ•ด Recaptcha๋ฅผ ํ†ตํ•ด ๊ฒ€์ฆ๋œ ์š”์ฒญ์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ๋‹ค.
new [๋ชจ๊ฐ์ฝ”24ํ•˜๊ณ„] 01 : ๊ฒฐ๊ณผ
๐Ÿ‘จโ€๐Ÿ’ป ๋ชจ๊ฐ์ฝ”
django์—์„œ swagger ๋ฌธ์„œํ™” ๊ตฌํ˜„ํ•˜๊ธฐ ๊ฐœ์š” ์žฅ๊ณ  ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ๋ณธ์ ์ธ CRUD ๊ธฐ๋Šฅ๊ณผ, REST API๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์•Œ์•„๋ณด์ž. ํ”„๋กœ์ ํŠธ ๊ตฌ์กฐ 1. 2โ”œโ”€โ”€ db.sqlite3 3โ”œโ”€โ”€ djtest (๋ฉ”์ธ ์•ฑ) 4โ”‚ โ”œโ”€โ”€ __init__.py 5โ”‚ โ”œโ”€โ”€ asgi.py 6โ”‚ โ”œโ”€โ”€ settings.py 7โ”‚ โ”œโ”€โ”€ urls.py 8โ”‚ โ”œโ”€โ”€ views.py 9โ”‚ โ””โ”€โ”€ wsgi.py 10โ”œโ”€โ”€ manage.py 11โ”œโ”€โ”€ paste (์ƒ์„ฑํ•œ ์•ฑ) 12โ”‚ โ”œโ”€โ”€ __init__.py 13โ”‚ โ”œโ”€โ”€ admin.py 14โ”‚ โ”œโ”€โ”€ apps.py 15โ”‚ โ”œโ”€โ”€ migrations 16โ”‚ โ”œโ”€โ”€ models.py 17โ”‚ โ”œโ”€โ”€ serializers.py 18โ”‚ โ”œโ”€โ”€ tests.py 19โ”‚ โ”œโ”€โ”€ urls.py 20โ”‚ โ””โ”€โ”€ views.py 21โ””โ”€โ”€ requirements.txt ์ž์ฃผ ์‚ฌ์šฉํ•˜๋Š” Django ๋ช…๋ น์ž 1# ์ƒˆ๋กœ์šด Django ํ”„๋กœ์ ํŠธ๋ฅผ ์ƒ์„ฑ 2python manage.py startproject 3# ์ƒˆ๋กœ์šด Django ์•ฑ์„ ์ƒ์„ฑ 4python manage.py startapp 5# ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ์šฉํ•  ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํŒŒ์ผ์„ ์ƒ์„ฑ 6python manage.py makemigrations 7# ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ ํŒŒ์ผ์„ ์‹ค์ œ ๋ฐ์ดํ„ฐ๋ฒ ์ด์Šค์— ์ ์šฉ 8python manage.py migrate 9# ๊ด€๋ฆฌ์ž(superuser) ๊ณ„์ •์„ ์ƒ์„ฑ 10python manage.py createsuperuser 11# ํ”„๋กœ์ ํŠธ์˜ ํ…Œ์ŠคํŠธ ์ผ€์ด์Šค๋ฅผ ์‹คํ–‰ 12python manage.py test 13# ํ…Œ์ŠคํŠธ์šฉ ์„œ๋ฒ„๋ฅผ ํŠน์ • ์„ค์ •์œผ๋กœ ์‹คํ–‰ 14python manage.py testserver CRUD ๊ตฌํ˜„ Paste ๋ชจ๋ธ ์ •์˜ 1from django.db import models 2 3class Paste(models.Model): 4 title = models.CharField(max_length=100) 5 content = models.TextField() 6 # auto_now_add : ๊ฐ์ฒด๊ฐ€ ์ฒ˜์Œ ์ƒ์„ฑ๋  ๋•Œ๋งŒ ํ˜„์žฌ ๋‚ ์งœ์™€ ์‹œ๊ฐ„์„ ์ž๋™์œผ๋กœ ์„ค์ • 7 created_at = models.DateTimeField(auto_now_add=True) 8 # auto_now : ๊ฐ์ฒด๊ฐ€ ์ €์žฅ๋  ๋•Œ๋งˆ๋‹ค ํ˜„์žฌ ๋‚ ์งœ์™€ ์‹œ๊ฐ„์„ ์ž๋™์œผ๋กœ ์„ค์ • 9 updated_at = models.DateTimeField(auto_now=True) 10 class Meta: 11 ordering = ['-created_at'] 12 def __str__(self): 13 return self.title Serializer ์ •์˜ 1from rest_framework import serializers 2from .models import Paste 3 4class PasteSerializer(serializers.ModelSerializer): 5 class Meta: 6 model = Paste 7 fields = '__all__' 8 # ์ง์ ‘ ์ง€์ •ํ•˜๋Š” ๋ฐฉ๋ฒ• 9 # fields = ['title', 'content'] View ๊ตฌํ˜„ PasteView 1class PasteView(APIView): 2 def get(self, _): 3 pastes = Paste.objects.all() 4 serializer = PasteSerializer(pastes, many=True) 5 return Response(serializer.data, status=status.HTTP_200_OK) 6 7 def post(self, request): 8 serializer = PasteSerializer(data=request.data) 9 if serializer.is_valid(): 10 serializer.save(user=request.user) 11 return Response(serializer.data, status=status.HTTP_201_CREATED) 12 return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) PasteDetailView 1class PasteDetailView(APIView): 2 def get(self, _, pk): 3 try: 4 paste = Paste.objects.get(pk=pk) 5 serializer = PasteSerializer(paste) 6 return Response(serializer.data, status=status.HTTP_200_OK) 7 except Paste.DoesNotExist: 8 return Response(status=status.HTTP_404_NOT_FOUND) 9 10 def put(self, request, pk): 11 try: 12 paste = Paste.objects.get(pk=pk) 13 except Paste.DoesNotExist: 14 return Response(status=status.HTTP_404_NOT_FOUND) 15 16 if paste.user != request.user: 17 return Response(status=status.HTTP_403_FORBIDDEN) 18 19 serializer = PasteSerializer(paste, data=request.data) 20 if serializer.is_valid(): 21 serializer.save() 22 return Response(serializer.data, status=status.HTTP_200_OK) 23 return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) 24 25 def delete(self, request, pk): 26 try: 27 paste = Paste.objects.get(pk=pk) 28 except Paste.DoesNotExist: 29 return Response(status=status.HTTP_404_NOT_FOUND) 30 31 paste.delete() 32 return Response(status=status.HTTP_204_NO_CONTENT) urls.py 1from django.urls import path 2from paste.views import * 3 4urlpatterns = [ 5 path('', PasteView.as_view(), name='paste_list_create'), 6 path('<int:pk>', PasteDetailView.as_view(), name='paste_get_update_delete'), 7] Swagger ์ ์šฉ PasteView PasteView 1class PasteView(APIView): 2 @swagger_auto_schema( 3 operation_description="Get list of pastes", 4 operation_summary="Get list of pastes", 5 responses={200: PasteSerializer(many=True)}, 6 ) 7 def get(self, _): 8 ... 9 10 @swagger_auto_schema( 11 operation_description="Create a new paste", 12 operation_summary="Create a new paste", 13 request_body=PasteSerializer, 14 responses={201: PasteSerializer, 400: "Bad Request"}, 15 ) 16 def post(self, request): 17 ... PasteDetailView 1class PasteDetailView(APIView): 2 @swagger_auto_schema( 3 operation_description="Get a paste by ID", 4 operation_summary="Get a paste by ID", 5 responses={200: PasteSerializer, 404: "Not Found"}, 6 ) 7 def get(self, _, pk): 8 ... 9 10 @swagger_auto_schema( 11 operation_description="Update a paste by ID", 12 operation_summary="Update a paste by ID", 13 request_body=PasteSerializer, 14 responses={ 15 200: PasteSerializer, 16 400: "Bad Request", 17 403: "Forbidden", 18 404: "Not Found", 19 }, 20 ) 21 def put(self, request, pk): 22 ... 23 24 @swagger_auto_schema( 25 operation_description="Delete a paste by ID", 26 operation_summary="Delete a paste by ID", 27 responses={204: "No Content", 404: "Not Found"}, 28 ) 29 def delete(self, request, pk): 30 ... swagger ์ ์šฉ ๊ฒฐ๊ณผ django์—์„œ JWT ์ธ์ฆ ๊ตฌํ˜„ํ•˜๊ธฐ ์žฅ๊ณ ์—์„œ๋Š” djangorestframework-simplejwt ํŒจํ‚ค์ง€๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ JWT ์ธ์ฆ์„ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ๋‹ค. requirements 1pip install djangorestframework-simplejwt settings.py 1INSTALLED_APPS = [ 2 ... 3 'rest_framework', 4 'rest_framework_simplejwt', 5] 1REST_FRAMEWORK = { 2 # ๊ธฐ๋ณธ ์ธ์ฆ ํด๋ž˜์Šค๋ฅผ ์„ค์ • 3 'DEFAULT_AUTHENTICATION_CLASSES': ( 4 'rest_framework_simplejwt.authentication.JWTAuthentication', 5 ), 6 # ๊ธฐ๋ณธ ์Šคํ‚ค๋งˆ ํด๋ž˜์Šค๋ฅผ ์„ค์ •, CoreAPI๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™์œผ๋กœ API ๋ฌธ์„œํ™”๋ฅผ ์ƒ์„ฑ 7 'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema', 8 # ๊ธฐ๋ณธ ๊ถŒํ•œ ํด๋ž˜์Šค๋ฅผ ์„ค์ •, AllowAny๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋ชจ๋“  ์š”์ฒญ์„ ํ—ˆ์šฉ 9 'DEFAULT_PERMISSION_CLASSES': ( 10 'rest_framework.permissions.AllowAny', 11 ), 12} 1from datetime import timedelta 2 3SIMPLE_JWT = { 4 # ์•ก์„ธ์Šค ํ† ํฐ์˜ ์œ ํšจ ๊ธฐ๊ฐ„์„ ์„ค์ • 5 'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30), 6 # ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์˜ ์œ ํšจ ๊ธฐ๊ฐ„์„ ์„ค์ • 7 'REFRESH_TOKEN_LIFETIME': timedelta(days=1), 8 # ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์ด ๊ฐฑ์‹ ๋  ๋•Œ๋งˆ๋‹ค ์ƒˆ๋กœ์šด ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์„ ๋ฐœ๊ธ‰ํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ์„ค์ • 9 'ROTATE_REFRESH_TOKENS': False, 10 # ๋ฆฌํ”„๋ ˆ์‹œ ํ† ํฐ์ด ๊ฐฑ์‹ ๋œ ํ›„ ์ด์ „ ํ† ํฐ์„ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ• ์ง€ ์—ฌ๋ถ€๋ฅผ ์„ค์ • 11 'BLACKLIST_AFTER_ROTATION': True, 12 13 # JWT ํ† ํฐ์˜ ์•”ํ˜ธํ™” ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์„ค์ • 14 'ALGORITHM': 'HS256', 15 # JWT ํ† ํฐ์„ ์„œ๋ช…ํ•  ๋•Œ ์‚ฌ์šฉํ•  ํ‚ค๋ฅผ ์„ค์ • 16 'SIGNING_KEY': SECRET_KEY, 17 # ํ† ํฐ ๊ฒ€์ฆ์— ์‚ฌ์šฉํ•  ๊ณต๊ฐœ ํ‚ค๋ฅผ ์„ค์ • 18 'VERIFYING_KEY': None, 19 # ํ† ํฐ์˜ ๋Œ€์ƒ์ž(aud) ํด๋ ˆ์ž„์„ ์„ค์ • 20 'AUDIENCE': None, 21 # ํ† ํฐ์˜ ๋ฐœ๊ธ‰์ž(iss) ํด๋ ˆ์ž„์„ ์„ค์ • 22 'ISSUER': None, 23 24 # ์ธ์ฆ ํ—ค๋” ํƒ€์ž…์„ ์„ค์ • 25 'AUTH_HEADER_TYPES': ('Bearer',), 26 # ์ธ์ฆ ํ—ค๋”์˜ ์ด๋ฆ„์„ ์„ค์ • 27 'AUTH_HEADER_NAME': 'HTTP_AUTHORIZATION', 28 # ์‚ฌ์šฉ์ž ๋ชจ๋ธ์—์„œ ์‚ฌ์šฉ์ž ID ํ•„๋“œ๋ฅผ ์„ค์ • 29 'USER_ID_FIELD': 'id', 30 # JWT ํ† ํฐ์—์„œ ์‚ฌ์šฉ์ž ID๋ฅผ ์ €์žฅํ•  ํด๋ ˆ์ž„์„ ์„ค์ • 31 'USER_ID_CLAIM': 'user_id', 32 33 # ์ธ์ฆ์— ์‚ฌ์šฉํ•  ํ† ํฐ ํด๋ž˜์Šค๋“ค์„ ์„ค์ • 34 'AUTH_TOKEN_CLASSES': ('rest_framework_simplejwt.tokens.AccessToken',), 35 # ํ† ํฐ์˜ ์œ ํ˜•์„ ์ €์žฅํ•  ํด๋ ˆ์ž„์„ ์„ค์ • 36 'TOKEN_TYPE_CLAIM': 'token_type', 37} urls.py 1from django.urls import path 2from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView 3from rest_framework_simplejwt.authentication import JWTAuthentication 4 5urlpatterns = [ 6 # JWT ํ† ํฐ์„ ๋ฐœ๊ธ‰ํ•˜๋Š” ๋ทฐ 7 path("token/", TokenObtainPairView.as_view(), name="token_obtain_pair"), 8 # JWT ํ† ํฐ์„ ๊ฐฑ์‹ ํ•˜๋Š” ๋ทฐ 9 path("token/refresh/", TokenRefreshView.as_view(), name="token_refresh"), 10] views.py 1from rest_framework import permissions 2from rest_framework_simplejwt.authentication import JWTAuthentication 3from drf_yasg.utils import swagger_auto_schema 4 5 6class PasteView(APIView): 7 8 def get(self, request): 9 ... 10 11 def post(self, request): 12 ... 13 14 def get_permissions(self): 15 # SAFE_METHODS : GET, HEAD, OPTIONS 16 if self.request.method in permissions.SAFE_METHODS: 17 self.permission_classes = [permissions.AllowAny] 18 else: 19 self.authentication_classes = [JWTAuthentication] 20 self.permission_classes = [permissions.IsAuthenticated] 21 return super().get_permissions() 22 23 24class PasteDetailView(APIView): 25 26 def get(self, request, pk): 27 ... 28 29 def put(self, request, pk): 30 ... 31 32 def delete(self, request, pk): 33 ... 34 35 def get_permissions(self): 36 # SAFE_METHODS : GET, HEAD, OPTIONS 37 if self.request.method in permissions.SAFE_METHODS: 38 self.permission_classes = [permissions.AllowAny] 39 else: 40 self.authentication_classes = [JWTAuthentication] 41 self.permission_classes = [permissions.IsAuthenticated] 42 return super().get_permissions() ๊ฒฐ๊ณผ TokenObtainPairView๋ฅผ ํ†ตํ•ด access token๊ณผ refresh token์„ ๋ฐœ๊ธ‰๋ฐ›์„ ์ˆ˜ ์žˆ๋‹ค. TokenRefreshView๋ฅผ ํ†ตํ•ด refresh token์„ ์‚ฌ์šฉํ•˜์—ฌ access token์„ ๊ฐฑ์‹ ํ•  ์ˆ˜ ์žˆ๋‹ค. access token๊ณผ refresh token์€ settings.py์—์„œ ์„ค์ •ํ•œ ์œ ํšจ ๊ธฐ๊ฐ„์— ๋”ฐ๋ผ ๋งŒ๋ฃŒ๋œ๋‹ค. Blacklist ์ ์šฉ settings.py 1INSTALLED_APPS = [ 2 ... 3 'rest_framework_simplejwt.token_blacklist', 4] 1SIMPLE_JWT = { 2 ... 3 # ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ํ† ํฐ์„ ์ถ”๊ฐ€ํ•  ๋•Œ ์‚ฌ์šฉํ•  ๋ชจ๋ธ์„ ์„ค์ • 4 'BLACKLIST_AFTER_ROTATION': True, 5} ๊ฒฐ๊ณผ TokenRefreshView๋ฅผ ํ†ตํ•ด ํ† ํฐ์ด ์žฌ๋ฐœ๊ธ‰๋  ๋•Œ, ์ด์ „ refresh token์„ ๋ธ”๋ž™๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€ํ•œ๋‹ค.
new Python์˜ GIL
๐Ÿ Python
GIL(Global Interpreter Lock) ํ•˜๋‚˜์˜ ์“ฐ๋ ˆ๋“œ๋งŒ ํŒŒ์ด์ฌ ๋ฐ”์ดํŠธ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ๊ฒƒ ํŒŒ์ด์ฌ์˜ ํ‘œ์ค€ ๊ตฌํ˜„์ธ CPython์—์„œ๋งŒ ์กด์žฌ ์žฅ์  Reference Counting ๊ธฐ๋ฐ˜ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ์˜ Race condition ๋ฐฉ์ง€ ๋ฐ์ดํ„ฐ ๋ฌด๊ฒฐ์„ฑ ๋ณด์žฅ : ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ ํŒŒ์ด์ฌ ๊ฐ์ฒด๋‚˜ ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ จ ์ž‘์—…์ด ์•ˆ์ „ํ•˜๊ฒŒ ์ˆ˜ํ–‰๋˜๋„๋ก ๋ณด์žฅ ํŒŒ์ด์ฌ Interpreter์˜ ๊ตฌํ˜„์„ ๋‹จ์ˆœํ™” : ๋ณต์žกํ•œ ๋ฝ ๋ฉ”์ปค๋‹ˆ์ฆ˜์ด ํ•„์š”์—†์Œ C ํ™•์žฅ ๋ชจ๋“ˆ์ด Thread-Safe ํ•˜์ง€ ์•Š๋”๋ผ๋„ ์•ˆ์ „ํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋„๋ก ๋ณด์žฅ ํ”Œ๋žซํผ ๋…๋ฆฝ์„ฑ ์œ ์ง€ : CPU ์•„ํ‚คํ…์ฒ˜๋ณ„ ๋™๊ธฐํ™” ๋ฉ”์ปค๋‹ˆ์ฆ˜์— ์˜์กดํ•˜์ง€ ์•Š์Œ ๋‹จ์  ๋ฉ€ํ‹ฐ์ฝ”์–ด CPU ํ™œ์šฉ ์ œํ•œ: ๋‹จ์ผ ์ฝ”์–ด๋งŒ ์‚ฌ์šฉ๋˜๋ฏ€๋กœ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์˜ ์ด์ ์„ ์–ป์„ ์ˆ˜ ์—†์Œ ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋”ฉ ์„ฑ๋Šฅ ์ €ํ•˜ : ์“ฐ๋ ˆ๋“œ ๊ฐ„ context switching์ด ๋นˆ๋ฒˆํ•˜๊ฒŒ ๋ฐœ์ƒ ๊ณต์ •์„ฑ ๋ฌธ์ œ : ํŠน์ • ์“ฐ๋ ˆ๋“œ๊ฐ€ GIL์„ ์žฅ์‹œ๊ฐ„ ์ ์œ ํ•˜๋ฉด starvation ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Œ Reference Counting ๊ฐ์ฒด๊ฐ€ ๋ช‡ ๋ฒˆ ์ฐธ์กฐ๋˜๋Š”์ง€๋ฅผ ์„ธ์–ด์„œ 0์ด ๋˜๋ฉด ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ํ•ด์ œํ•˜๋Š” ๋ฐฉ์‹ ํŒŒ์ด์ฌ์ด ์‚ฌ์šฉํ•˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ด€๋ฆฌ ๋ฐฉ์‹ ์žฅ์  : ๋ฉ”๋ชจ๋ฆฌ ํ•ด์ œ๊ฐ€ ์ฆ‰์‹œ ์ด๋ฃจ์–ด์ง ๋‹จ์  : Reference Counting์ด ๋ณต์žกํ•œ ๊ฐ์ฒด ์‚ฌ์ด์˜ ์ˆœํ™˜ ์ฐธ์กฐ๋ฅผ ํ•ด๊ฒฐํ•˜์ง€ ๋ชปํ•จ IO Bound Task vs CPU Bound Task IO Bound Task : ํŒŒ์ผ ์ฝ๊ธฐ/์“ฐ๊ธฐ, ๋„คํŠธ์›Œํฌ ํ†ต์‹  ๋“ฑ์˜ ์ž‘์—… CPU Bound Task : ๊ณ„์‚ฐ๋Ÿ‰์ด ๋งŽ์€ ์ž‘์—… GIL์ด ์ฃผ๋Š” ์˜ํ–ฅ IO Bound Task : I/O์ž‘์—…์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๋™์•ˆ GIL์ด ํ•ด์ œ๋˜์–ด ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์žˆ์Œ -> ์˜ํ–ฅ์ด ์ ์Œ CPU Bound Task : GIL์ด ํ•ด์ œ๋˜์ง€ ์•Š์•„ ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ๊ฐ€ ์‹คํ–‰๋  ์ˆ˜ ์—†์Œ -> ์†ํ•ด๊ฐ€ ๋ฐœ์ƒ ๋Œ€์•ˆ multiprocessing ๋ชจ๋“ˆ ์‚ฌ์šฉ C ํ™•์žฅ ๋ชจ๋“ˆ ์‚ฌ์šฉ Jython, IronPython ๋“ฑ์˜ GIL์ด ์—†๋Š” ํŒŒ์ด์ฌ ๊ตฌํ˜„ ์‚ฌ์šฉ
new Github Actions์—์„œ pytest ์‹คํ–‰ํ•˜๊ธฐ
๐Ÿ Python
๋ฐฐ๊ฒฝ ํ…Œ์ปค ๋ถ€ํŠธ์บ ํ”„์—์„œ ํŒ€ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ ์ค‘์ด๋‹ค. ํ˜„์žฌ ๋น„์ฆˆ๋‹ˆ์Šค ๋กœ์ง์„ ์ˆ˜ํ–‰ํ•˜๋Š” ํ•จ์ˆ˜๋ฅผ ๋Œ€์ƒ์œผ๋กœ Unit Test๊ฐ€ ํ•„์š”ํ•˜๋‹ค. Unit Test ์ฝ”๋“œ๋ฅผ ์ž‘์„ฑํ•˜๊ณ , Github Actions๋ฅผ ์ด์šฉํ•˜์—ฌ ์ž๋™์œผ๋กœ ํ…Œ์ŠคํŠธ๊ฐ€ ์ˆ˜ํ–‰๋˜๋„๋ก ์„ค์ •ํ•˜๊ณ ์ž ํ•œ๋‹ค. run-pytest.yml 1name: Run pytest 2 3# main ๋˜๋Š” dev ๋ธŒ๋žœ์น˜์— pull request๊ฐ€ ๋ฐœ์ƒํ•˜๋ฉด ์‹คํ–‰ 4on: 5 pull_request: 6 branches: 7 - main 8 - dev 9 10jobs: 11 test: 12 runs-on: ubuntu-latest 13 14 steps: 15 - name: Checkout code 16 uses: actions/checkout@v2 17 18 - name: Set up Python 19 uses: actions/setup-python@v2 20 with: 21 python-version: '3.12' 22 23 - name: Install dependencies 24 run: | 25 python -m pip install --upgrade pip 26 pip install -r requirements.txt 27 28 - name: Run tests 29 run: pytest . ๊ฒฐ๊ณผ Run pytest . ============================= test session starts ============================== platform linux -- Python 3.12.4, pytest-8.2.2, pluggy-1.5.0 rootdir: /home/runner/work/Backend/Backend plugins: anyio-4.4.0 collected 13 items app/tests/test_crud_chatroom.py ... [ 23%] app/tests/test_crud_mentor.py ... [ 46%] app/tests/test_crud_prescription.py ... [ 69%] app/tests/test_crud_user.py .... [100%] ============================== 13 passed in 0.58s ============================== ์ƒ๊ฐ๋ณด๋‹ค ๊ฐ„๋‹จํ•˜๊ฒŒ ๊ตฌํ˜„ํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ํ…Œ์ŠคํŠธ ์ปค๋ฒ„๋ฆฌ์ง€ 100% ์ฐ๊ณ , CD๊นŒ์ง€ ๊ตฌํ˜„ํ•˜๋ฉด ๋”ํ•  ๋‚˜์œ„ ์—†์„ ๊ฒƒ ๊ฐ™๋‹ค.
new Python์˜ ๋™์ž‘ ์›๋ฆฌ
๐Ÿ Python
ํŒŒ์ด์ฌ์˜ ๊ตฌํ˜„์ฒด CPython ํŒŒ์ด์ฌ์˜ ํ‘œ์ค€ ๊ตฌํ˜„์ฒด์ด์ž ์ธํ„ฐํ”„๋ฆฌํ„ฐ ์—ญํ•  ํŒŒ์ด์ฌ ์ฝ”๋“œ๋ฅผ ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜ ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ ํŒŒ์ด์ฌ ๋ฐ”์ดํŠธ ์ฝ”๋“œ .pyc ํŒŒ์ผ์— ์ €์žฅ ํ”Œ๋žซํผ์— ๋…๋ฆฝ์  ํŒŒ์ด์ฌ ๊ฐ€์ƒ ๋จธ์‹ (PVM)์—์„œ ์‹คํ–‰ ์˜ˆ์‹œ 4 0 LOAD_GLOBAL 0 (print) 2 LOAD_CONST 1 ('hello world') 4 CALL_FUNCTION 1 6 POP_TOP 5 8 LOAD_CONST 2 (True) 10 RETURN_VALUE Jython ํŒŒ์ด์ฌ ์ฝ”๋“œ๋ฅผ ์ž๋ฐ” ๋ฐ”์ดํŠธ ์ฝ”๋“œ๋กœ ๋ณ€ํ™˜, JVM์—์„œ ์‹คํ–‰ ์žฅ์  : ์ž๋ฐ” ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ˜ธ์ถœ, ์ž๋ฐ” ํด๋ž˜์Šค ์‚ฌ์šฉ ๊ฐ€๋Šฅ, GIL ์—†์Œ ๋‹จ์  : ํŒŒ์ด์ฌ 3.x ์ง€์›ํ•˜์ง€ ์•Š์Œ, CPython ๋Œ€๋น„ ์†๋„๊ฐ€ ๋А๋ฆผ PyPy ํŒŒ์ด์ฌ ์ฝ”๋“œ๋ฅผ JIT ์ปดํŒŒ์ผํ•˜์—ฌ ์‹คํ–‰ RPython(Restricted Python)์œผ๋กœ ์ž‘์„ฑ๋œ ํŒŒ์ด์ฌ ์ธํ„ฐํ”„๋ฆฌํ„ฐ ์ ‘๊ทผ ๋ฐฉ์‹ RPython(์—„๊ฒฉํ•œ ํŒŒ์ด์ฌ)์„ ๋งŒ๋“ค์–ด ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋ฅผ ์ž‘์„ฑ RPython์˜ ํšจ๊ณผ์ ์ธ ์ปดํŒŒ์ผ์„ ์œ„ํ•ด ๋‹ค๋ฅธ ์–ธ์–ด๋กœ ํˆด์ฒด์ธ์„ ์ œ์ž‘ Python ๊ตฌํ˜„์„ RPython ๋ฌธ๋ฒ•์œผ๋กœ ์ž‘์„ฑ 3์—์„œ ๋งŒ๋“  ๊ตฌํ˜„์„ 1, 2๋ฅผ ํ†ตํ•ด ์–ป์€ ์ธํ„ฐํ”„๋ฆฌํ„ฐ๋กœ ์ปดํŒŒ์ผ 4์—์„œ ๋งŒ๋“  ํ›„๋ณด๋“ค์˜ ์„ฑ๋Šฅ์„ ์ธก์ •ํ•˜๊ณ , ๊ฐœ์„  5์˜ ์‚ฐ์ถœ๋ฌผ์„ ์ถœ์‹œ, ๋‹ค์‹œ ๋ฐ˜๋ณต ์žฅ๋‹จ์  ์žฅ์  : CPython ๋Œ€๋น„ ๋น ๋ฅธ ์†๋„, ๋‹ค์–‘ํ•œ ํ”Œ๋žซํผ ์ง€์› ๋‹จ์  : ํŠน์ • ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ํ˜ธํ™˜์„ฑ ๋ฌธ์ œ๊ฐ€ ์กด์žฌ, ๋ฉ”๋ชจ๋ฆฌ ์‚ฌ์šฉ๋Ÿ‰์ด ํผ
new Issue - fastapi์—์„œ websocket 404 ๋ฌธ์ œ
๐Ÿ Python
๋ฐฐ๊ฒฝ ํ…Œ์ปค ๋ถ€ํŠธ์บ ํ”„ ์ตœ์ข…๋ฐœํ‘œ ์ „๋‚ ์ด๋‹ค. gpt ํ”„๋กฌํ”„ํŠธ ๋ถ€๋ถ„ ์ˆ˜์ •์„ main ๋ธŒ๋žœ์น˜์— ๋ฐ˜์˜ํ•˜๊ณ , EC2 ์„œ๋ฒ„์— ๋ฐฐํฌํ–ˆ๋‹ค. ๋ฌธ์ œ ๋ฐฐํฌํ•œ ์„œ๋ฒ„์—์„œ websocket ์—ฐ๊ฒฐ์ด 404 ์—๋Ÿฌ๋ฅผ ๋ฐ˜ํ™˜ํ•œ๋‹ค. (๋‚ด์ผ์ด ์ตœ์ข… ๋ฐœํ‘œ์ธ๋ฐ,,,) ๋‹ค๋ฅธ http ์š”์ฒญ์€ ์ •์ƒ์ ์œผ๋กœ ์ฒ˜๋ฆฌ๋˜์ง€๋งŒ ์›น์†Œ์ผ“๋งŒ ์ฒ˜๋ฆฌ๋˜์ง€ ์•Š๋Š” ๊ฒƒ์„ ํ™•์ธํ–ˆ๋‹ค. nginx์˜ log 1{IP์ฃผ์†Œ} - - [02/Aug/2024:10:59:04 +0000] "GET /ws/chatrooms/294?user_id=296 HTTP/1.1" 404 22 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15" 2{IP์ฃผ์†Œ} - - [02/Aug/2024:10:59:05 +0000] "GET /ws/chatrooms/294?user_id=296 HTTP/1.1" 404 22 "-" "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.5 Safari/605.1.15" ์‚ฌ๊ณ ํ๋ฆ„ nginx ์„ค์ • ๋ฌธ์ œ์ธ๊ฐ€? X nginx ์„ค์ •์€ ๋ณ€๊ฒฝ๋˜์ง€ ์•Š์•˜๋‹ค. ๋ฐฐํฌํ™˜๊ฒฝ์˜ ๋ฌธ์ œ์ธ๊ฐ€? X ๋กœ์ปฌ์—์„œ ์‹คํ–‰ํ•œ ์„œ๋ฒ„์—์„œ๋„ ๋™์ผํ•œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค. ์ด๋ฒˆ ๋ฐฐํฌ์—์„œ ๋ณ€๊ฒฝ๋œ ์†Œ์Šค์ฝ”๋“œ๊ฐ€ ๋ฌธ์ œ์ธ๊ฐ€? X ์œก์•ˆ์œผ๋กœ ํ™•์ธํ–ˆ์„ ๋•Œ๋Š”, ๋ณ€๊ฒฝ๋œ ๋ถ€๋ถ„์ด ์›น์†Œ์ผ“๊ณผ ๊ด€๋ จ์ด ์—†๋‹ค. ๋กœ์ปฌ์—์„œ ์ด์ „ ๋ฒ„์ „์œผ๋กœ reset ํ›„ ์‹œ๋„ ํ•ด๋ณด์•˜์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์•˜๋‹ค. Docker image ๋ฌธ์ œ์ธ๊ฐ€? X ๋ฐฑ์—”๋“œ ์„œ๋ฒ„๋Š” python:slim ์ด๋ฏธ์ง€๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ์œผ๋ฉฐ, ํ•ด๋‹น ์ด๋ฏธ์ง€๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด์„œ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•  ๊ฐ€๋Šฅ์„ฑ์ด ์žˆ๋‹ค๊ณ  ์ƒ๊ฐํ–ˆ๋‹ค. ๋กœ์ปฌ์—์„œ docker image๋ฅผ ์‚ฌ์šฉํ•˜์ง€ ์•Š๊ณ  ์‹คํ–‰ํ•ด๋ณด์•˜์ง€๋งŒ ๋ฌธ์ œ๊ฐ€ ํ•ด๊ฒฐ๋˜์ง€ ์•Š์•˜๋‹ค. ์ด๋•Œ, ๋กœ๊ทธ์—์„œ warning ๋ฉ”์‹œ์ง€๋ฅผ ํ™•์ธํ–ˆ๋‹ค. WARNING: No supported WebSocket library detected. Please use "pip install 'uvicorn[standard]'", or install 'websockets' or 'wsproto' manually. ์›์ธ ๋ชจ์ข…์˜ ์ด์œ ๋กœ, ์ด์ „์— ๊ฐœ๋ฐœ/๋ฐฐํฌํ• ๋•Œ์—๋Š” ์กด์žฌํ–ˆ๋˜ ์›น์†Œ์ผ“ ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์‚ฌ๋ผ์ง„ ๊ฒƒ์ด๋‹ค. ์˜ค๋ฅ˜๋ฅผ ํ•ด๊ฒฐํ•˜๊ณ  ์กฐ์‚ฌํ•ด๋ณธ ๊ฒฐ๊ณผ fastapi ๋ ˆํฌ์ง€ํ† ๋ฆฌ์— 6์‹œ๊ฐ„ ์ „ merge๋œ PR์„ ํ™•์ธํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. (https://github.com/fastapi/fastapi/pull/11935) ํ•ด๋‹น PR์—์„œ๋Š” pip install fastapi[standard] ๋ฅผ ํ†ตํ•ด ํ‘œ์ค€ ์ข…์† ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜๋Š” ๊ธฐ๋Šฅ์ด ์ถ”๊ฐ€๋˜์—ˆ๋‹ค. ์ด๋กœ ์ธํ•ด, uvicorn[standard] ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์„ค์น˜ํ•˜์ง€ ์•Š์•˜์„ ๋•Œ, ์›น์†Œ์ผ“ ๊ด€๋ จ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์„ค์น˜๋˜์ง€ ์•Š์•„ ๋ฐœ์ƒํ•œ ๋ฌธ์ œ์˜€๋‹ค. ํ•ด๊ฒฐ requirements.txt์— websockets๋ฅผ ์ถ”๊ฐ€ํ•ด์„œ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค. ๋ฐฐ์šด ์  ์ค‘์š”ํ•œ ํ”„๋กœ์ ํŠธ๋ฅผ ํ•  ๋•Œ requirements.txt์— ํ•ญ์ƒ ๊ฐ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์— ๋ฒ„์ „์„ ๋ช…์‹œํ•ด์•ผ๊ฒ ๋‹ค๋Š” ์ƒ๊ฐ์ด ๋“ค์—ˆ๋‹ค. ์ด๋ฒˆ์—๋„ ๋ฒ„์ „์„ ๋ช…์‹œํ–ˆ๋‹ค๋ฉด, ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์—…๋ฐ์ดํŠธ ๋˜๋”๋ผ๋„ ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์ง€ ์•Š์•˜์„ ๊ฒƒ์ด๋‹ค. ๋˜ํ•œ, ๋กœ๊ทธ๋ฅผ ์ž˜ ํ™•์ธํ•˜๊ณ , warning ๋ฉ”์‹œ์ง€๋ฅผ ๋†“์น˜์ง€ ์•Š๋„๋ก ์ฃผ์˜ํ•ด์•ผ๊ฒ ๋‹ค.
new 230315 ๊ธฐํ”„๋žฉ Design Thinking ๋ฐฉ๋ฒ•๋ก  - ๊น€์žฌ์ • ๊ต์ˆ˜๋‹˜
๐Ÿซ ํ•™๊ณผ ๊ณต๋ถ€
๋””์ž์ธ ์”ฝํ‚น์ด๋ž€ ๊ณต๊ฐ์˜ ๊ณผ์ •์„ ํ†ตํ•ด ๋ฌธ์ œ์ ์„ ์ฐพ์•„๋‚ด๊ณ , ์•„์ด๋””์–ด๋ฅผ ๋ฐœ์‚ฐํ•˜๊ณ , ํ”„๋กœํ† ํƒ€์ž…์„ ๋งŒ๋“ค์–ด ๊ฒ€์ฆ ๊ณผ์ •์„ ๊ฑฐ์น˜๋Š”, ๋ฐ˜๋ณต์  ํ”„๋กœ์„ธ์Šค์— ๋Œ€ํ•œ ๋ฐฉ๋ฒ•๋ก  ๋ฐ ์‚ฌ๊ณ ๋ฐฉ์‹ ๋””์ž์ธ ์”ฝํ‚น ํ”„๋กœ์„ธ์Šค ๊ณต๊ฐ - ๋ฌธ์ œ ์ •์˜ - ์•„์ด๋””์–ด ๋„์ถœ - ํ”„๋กœํ† ํƒ€์ดํ•‘ - ํ…Œ์ŠคํŒ… 1. ๊ณต๊ฐ ๊ณต๊ฐ ํ”„๋กœ์„ธ์Šค ๋ฉด๋‹ดํ•˜๊ธฐ ๊ด€์ฐฐํ•˜๊ธฐ ๊ฒฝํ—˜ํ•˜๊ธฐ ๋ฉด๋‹ด์ง€ ์ค€๋น„ํ•˜๊ธฐ ์ˆœ์ฐจ์  ๊ฒฝํ—˜ ์งˆ๋ฌธ : ์–ด๋–ค ์ˆœ์„œ๋กœ ํ–‰๋™ํ•˜๊ณ  ๊ฒฝํ—˜ํ•˜๋Š”์ง€ ๋ฌผ์–ด๋ณด์ž ๊ฐ์ • ์งˆ๋ฌธ ์ด์œ  ์งˆ๋ฌธ : ํ–‰๋™ ๋˜๋Š” ๊ฐ์ •์— ๋Œ€ํ•œ ์ด์œ ๋ฅผ ๋ฌผ์–ด๋ณด์ž ๋˜ ์งˆ๋ฌธ : “๋˜…“๋ผ๋Š” ์งˆ๋ฌธ์„ ๋งŽ์ด ํ•˜์ž ๊ตฌ์ฒดํ™” ์งˆ๋ฌธ ๊ด€์ฐฐํ•˜๊ธฐ | ๋ชจ๋‹ˆํ„ฐ๋ง ํ˜„์žฅ ์ค‘์‹ฌ ๊ด€์ฐฐ : ์„ธ์ƒ์„ ๋„“๊ณ  ๊นŠ๊ฒŒ ๋ฐ”๋ผ๋ณด๊ธฐ ๊ด€์ฐฐํ•˜๊ธฐ | ์‰๋„์ž‰ ์‚ฌ๋žŒ์˜ ์ฒดํ—˜์ด๋‚˜ ํ–‰๋™์„ ๊ทธ์ž๋ฆฌ์—์„œ ๊ด€์ฐฐํ•˜๊ธฐ ๊ด€์ฐฐํ•˜๊ธฐ | ๋งฅ๋ฝ ์งˆ์˜๋ฒ• ํ˜„์žฅ์—์„œ ๊ด€์ฐฐ ๋ฐ ๋ฉด๋‹ด์„ ํ†ตํ•ด ๋Œ€์ƒ์ž์— ๋Œ€ํ•œ ์ดํ•ด๋ฅผ ํ•˜๋Š” ๋ฐฉ๋ฒ• ๋งฅ๋ฝ ์งˆ์˜๋ฒ•์˜ 4๊ฐ€์ง€ ์›์น™ ๋งฅ๋ฝ : ๋Œ€์ƒ์ž์˜ ์ž‘์—…ํ™˜๊ฒฝ์— ๋Œ€ํ•œ ๋””ํ…Œ์ผ์„ ๊ด€์ฐฐํ•˜๋ผ ํŒŒํŠธ๋„ˆ์‹ญ : ๋Œ€์ƒ์ž๋ฅผ ๊ณต๊ฐํ•˜๋ผ ํ•ด์„ : ์—ฐ๊ตฌ์ž๋Š” ๋Œ€์ƒ์ž์—๊ฒŒ ๋ณธ์ธ์˜ ํ•ด์„์„ ๊ณต์œ ํ•˜๋ผ ํฌ์ปค์Šค : ํ•ต์‹ฌ ๋ชฉํ‘œ ์ฃผ์ œ์—์„œ ๋ฒ—์–ด๋‚˜์ง€ ๋งˆ๋ผ ๋งฅ๋ฝ ์งˆ์˜๋ฒ• ์ˆ˜ํ–‰ํ•˜๊ธฐ ์ค€๋น„ํ•˜๊ธฐ, ๊ธฐ๋กํ•˜๊ธฐ ๋„์ œ๊ด€๊ณ„ ๋ชจ๋ธ (Master-apprentice Model) ๋งˆ์Šคํ„ฐ(๋Œ€์ƒ์ž)๊ฐ€ ํ•ด๋‹น ์—…๋ฌดํ™˜๊ฒฝ์—์„œ ์ž์‹ ์˜ ์ƒ๊ฐ๊ณผ ํ–‰๋™์„ ์†Œ๋ฆฌ๋‚ด์–ด ๋งํ•˜๊ฒŒ ํ•œ๋‹ค ์—ฐ๊ตฌ์ž๋Š” ๊ฒฌ์Šต์ƒ์ด ๋˜์–ด ์ค‘๊ฐ„์ค‘๊ฐ„ ๋ฌผ์–ด๋ณด๋ฉด์„œ ํ•™์Šตํ•œ๋‹ค ์†Œ๋ฆฌ๋‚ด์–ด ์ƒ๊ฐํ•˜๊ธฐ (Think Aloud) ๊ธฐ๋ฒ• ๋ณ‘ํ–‰์‹ : ๊ณผ์—…์„ ํ•˜๋Š” ๊ณผ์ •์—์„œ ์‹ค์‹œ๊ฐ„์œผ๋กœ ์ด์•ผ๊ธฐ ํ•œ๋‹ค ํšŒ๊ณ ์‹ : ๋‹จ๊ณ„๋ณ„ ๊ณผ์—…์„ ๋๋‚ด๊ณ  ์ด์•ผ๊ธฐํ•œ๋‹ค ๋ณ‘ํ–‰+ํšŒ๊ณ  ํ•˜์ด๋ธŒ๋ฆฌ๋“œ 2. ๋ฌธ์ œ์ •์˜ ํŽ˜๋ฅด์†Œ๋‚˜ ๋งŒ๋“ค๋ฌผ ํŽ˜๋ฅด์†Œ๋‚˜ : ํŠน์ • ์ƒํ™ฉ์—์„œ ์–ด๋–ป๊ฒŒ ํ–‰๋™ํ•˜๊ณ  ๋ฐ˜์‘ํ•˜๋Š”์ง€ ์ดํ•ดํ•˜๊ธฐ ์œ„ํ•ด ๋งŒ๋“  ๊ฐ€์ƒ์˜ ์ธ๋ฌผ, ์†”๋ฃจ์…˜์˜ ์ˆ˜ํ˜œ์ž POV ์ •์˜ํ•˜๊ธฐ ํŽ˜๋ฅด์†Œ๋‚˜์˜ ๊ด€์ ์—์„œ 1๊ฐœ์˜ POV๋กœ ์••์ถ•ํ•˜์ž POV(Point of View) ํŽ˜๋ฅด์†Œ๋‚˜๋Š” ๋ˆ„๊ตฌ์ธ๊ฐ€? ํŽ˜๋ฅด์†Œ๋‚˜๊ฐ€ ์›ํ•˜๋Š”๊ฒƒ์€ ๋ฌด์—‡์ธ๊ฐ€? ํŽ˜๋ฅด์†Œ๋‚˜์—๊ฒŒ ๊ทธ๊ฒƒ์ด ์ค‘์š”ํ•œ ์ด์œ ๋Š” ๋ฌด์—‡์ธ๊ฐ€? HMW ์ •์˜ํ•˜๊ธฐ ๊ตฌ์ฒด์ ์ธ ์•„์ด๋””์–ด๋ฅผ ๋‚ด๊ธฐ ์œ„ํ•œ ๋ธŒ๋ ˆ์ธ์Šคํ† ๋ฐ ๊ณผ์ • POV๋กœ ๋ถ€ํ„ฐ ํŒŒ์ƒ๋˜๋ฉฐ “์ˆ˜ํ–‰ ๊ฐ€๋Šฅํ•œ ๋‹จ์œ„"๋กœ ์ •์˜ ํ˜•์‹ : (์šฐ๋ฆฌ๋Š”) ์–ด๋–ป๊ฒŒ ~~~ ํ• ๊ฒƒ ์ธ๊ฐ€ ๊ณ ๊ฐ์—ฌ์ • ์ง€๋„ 3. ์•„์ด๋””์–ด ๋„์ถœ ๋ธŒ๋ ˆ์ธ์Šคํ† ๋ฐ ์˜ค์ฆˆ๋ณธ์˜ 4์›์น™ ๋น„ํŒ๊ธˆ์ง€ ์ž์œ ๋ถ„๋ฐฉ ์งˆ๋ณด๋‹ค ์–‘ Idea ํŽธ์Šน ์–ดํ”ผ๋‹ˆํ‹ฐ ๋‹ค์ด์–ด๊ทธ๋ž˜๋ฐ (์นœํ™”๋„๋ฒ•) ์ˆ˜์ง‘ํ•œ ๋ฐ์ดํ„ฐ๋ฅผ ์ •๋ฆฌํ•˜๋Š” ๋ฐฉ๋ฒ• ๋ฐ์ดํ„ฐ์—์„œ ๊ณตํ†ต๋œ ์ด์Šˆ/๋ฌธ์ œ/ํ•„์š”์„ฑ ๋“ฑ์„ ๋„์ถœํ•  ์ˆ˜ ์žˆ์Œ ์š”์•ฝํ•˜์—ฌ ํฌ์ŠคํŠธ์ž‡์— ๊ธฐ๋ก, ์œ ์‚ฌํ•œ ํ…Œ๋งˆ, ํ† ํ”ฝ์œผ๋กœ ๊ทธ๋ฃนํ™” ๋‹ค์–‘ํ•œ ์•„์ด๋””์–ด ๋„์ถœ ๋ฐฉ๋ฒ• ์˜์‚ฌ๊ฒฐ์ • ๊ทธ๋ฆฌ๋“œ (๊ธด๊ธ‰๋„, ์ค‘์š”๋„) 10+10 ๋ฐฉ๋ฒ• (10๊ฐœ์˜ ์•„์ด๋””์–ด, 10๊ฐœ์˜ ์†”๋ฃจ์…˜) ์•„์ด๋””์–ด ํ‰๊ฐ€ ํ…Œ์ด๋ธ” (์ ์ˆ˜ ๋งค๊ธฐ๊ธฐ) ์•„์ด๋””์–ด๋ฅผ ์ปจ์…‰์œผ๋กœ ์—ฎ๊ธฐ 4. Prototype ์Šคํ† ๋ฆฌ๋ณด๋“œ ์Šคํ† ๋ฆฌ๋ณด๋“œ๋Š” ์ œํ’ˆ ์‚ฌ์šฉ์˜ ํ™˜๊ฒฝ, ์ ˆ์ฐจ, ๋‹ˆ์ฆˆ ์ถฉ์กฑ ์š”์†Œ๊ฐ€ ํฌํ•จ๋œ๋‹ค ์Šคํ† ๋ฆฌ๋ณด๋”ฉ ์ ˆ์ฐจ ์Šคํ† ๋ฆฌ๋ผ์ธ ๋งŒ๋“ค๊ธฐ ๋ฉ”์ธ ์„ค์ •์ƒท ๊ทธ๋ฆฌ๊ธฐ ํ•ต์‹ฌ ์•„์ด๋””์–ด์˜ ์ „๋‹ฌ์„ ์œ„ํ•œ ์ ์ ˆํ•œ ์นด๋ฉ”๋ผ ๊ตฌ๋„ ์„ค์ • ๋ฐ ๊ทธ๋ฆฌ๊ธฐ ํ–‰๋™๊ณผ ์›€์ง์ž„ ๊ฐ•์กฐ ์ฒ˜๋ฆฌํ•˜๊ธฐ ์‚ฌ๋žŒ๋“ค์—๊ฒŒ ์‹œ์—ฐ ํ›„ ํ”ผ๋“œ๋ฐฑ ๋ฐ›๊ณ  ์ˆ˜์ •ํ•˜๊ธฐ
new ์ž๋ฃŒ๊ตฌ์กฐ
๐Ÿซ ํ•™๊ณผ ๊ณต๋ถ€
์ œ 1์žฅ : ์ž๋ฃŒ๊ตฌ์กฐ๋ฅผ ๋ฐฐ์šฐ๊ธฐ ์œ„ํ•œ ์ค€๋น„ (230302) ๋ฐฐ์—ด ๋ฐฐ์—ด(Array): ๋™์ผํ•œ ํƒ€์ž…์˜ ์›์†Œ๋“ค์ด ์—ฐ์†์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์— ํ• ๋‹น๋˜์–ด ์žˆ๋Š” ๊ธฐ์ดˆ์ ์ธ ์ž๋ฃŒ๊ตฌ์กฐ ์ถ”์ƒ๋ฐ์ดํ„ฐ ํƒ€์ž… ์ถ”์ƒ๋ฐ์ดํ„ฐํƒ€์ž…(ADT:Abstract Data Type) : ๋ฐ์ดํ„ฐ์™€ ๊ทธ ๋ฐ์ดํ„ฐ์— ๋Œ€ํ•œ ์ถ”์ƒ์ ์ธ ์—ฐ์‚ฐ๋“ค๋กœ์จ ๊ตฌ์„ฑ ADT =~ ์ž๋ฐ”์˜ interface, ์ž๋ฃŒ๊ตฌ์กฐ =~ ์ž๋ฐ”์˜ class ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ์ถ”์ƒ๋ฐ์ดํ„ฐํƒ€์ž…์„ ๊ตฌ์ฒด์ ์œผ๋กœ ๊ตฌํ˜„ํ•œ ๊ฒƒ 1-2 ์ˆ˜ํ–‰์‹œ๊ฐ„์˜ ๋ถ„์„ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์„ฑ๋Šฅ: ์ˆ˜ํ–‰์‹œ๊ฐ„์„ ๋‚˜ํƒ€๋‚ด๋Š” **์‹œ๊ฐ„๋ณต์žก๋„(Time Complexity)**์™€ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์ˆ˜ํ–‰๋˜๋Š” ๋™์•ˆ ์‚ฌ์šฉ๋˜๋Š” ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์˜ ํฌ๊ธฐ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” **๊ณต๊ฐ„๋ณต์žก๋„(Space Complexity)**์— ๊ธฐ๋ฐ˜ํ•˜์—ฌ ๋ถ„์„ ์‹œ๊ฐ„ ๋ณต์žก๋„ ์‹œ๊ฐ„๋ณต์žก๋„๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜(์—ฐ์‚ฐ)์ด ์‹คํ–‰๋˜๋Š” ๋™์•ˆ์— ์‚ฌ์šฉ๋œ ๊ธฐ๋ณธ์ ์ธ ์—ฐ์‚ฐ ํšŸ์ˆ˜๋ฅผ ์ž…๋ ฅ ํฌ๊ธฐ์˜ ํ•จ์ˆ˜๋กœ ๋‚˜ํƒ€๋‚ธ๋‹ค. ๊ธฐ๋ณธ ์—ฐ์‚ฐ(Elementary Operation)์ด๋ž€ ๋ฐ์ดํ„ฐ ๊ฐ„ ํฌ๊ธฐ ๋น„๊ต, ๋ฐ์ดํ„ฐ ์ฝ๊ธฐ ๋ฐ ๊ฐฑ์‹ , ์ˆซ์ž ๊ณ„์‚ฐ ๋“ฑ๊ณผ ๊ฐ™์€ ๋‹จ์ˆœํ•œ ์—ฐ์‚ฐ์„ ์˜๋ฏธ 4๊ฐ€์ง€ ์ข…๋ฅ˜์˜ ๋ถ„์„ ์ตœ์•…๊ฒฝ์šฐ ๋ถ„์„(Worst-case Analysis) : ์ƒํ•œ์„ ์˜ ์˜๋ฏธ ํ‰๊ท ๊ฒฝ์šฐ ๋ถ„์„(Average-case Analysis) ์ตœ์„ ๊ฒฝ์šฐ ๋ถ„์„(Best-case Analysis) : ๊ฐ€์žฅ ๋น ๋ฅธ ์ˆ˜ํ–‰์‹œ๊ฐ„ ์ƒ๊ฐ๋ถ„์„(Amortized Analysis) : ์ด ์—ฐ์‚ฐํšŸ์ˆ˜๋ฅผ ํ•ฉํ•˜๊ณ  ์—ฐ์‚ฐ ํšŸ์ˆ˜๋กœ ๋‚˜๋ˆ„์–ด ์ˆ˜ํ–‰์‹œ๊ฐ„์„ ๋ถ„์„ 1-3 ์ˆ˜ํ–‰์‹œ๊ฐ„์˜ ์ ๊ทผํ‘œ๊ธฐ๋ฒ• O (Big-Oh)-ํ‘œ๊ธฐ๋ฒ• ฮฉ (Big-Omega)-ํ‘œ๊ธฐ๋ฒ• ฮ˜ (Theta)-ํ‘œ๊ธฐ๋ฒ• O (Big-Oh) ํ‘œ๊ธฐ๋ฒ• ๋ชจ๋“  N โ‰ฅ N0์— ๋Œ€ํ•ด์„œ f(N) โ‰ค cg(N)์ด ์„ฑ๋ฆฝํ•˜๋Š” ์–‘์˜ ์ƒ์ˆ˜ c์™€N0๊ฐ€ ์กด์žฌํ•˜๋ฉด, f(N) = O(g(N))์ด๋‹ค. ๋ชจ๋“  N โ‰ฅ N0์— ๋Œ€ํ•ด์„œ f(N) โ‰ค cg(N)์ด ์„ฑ๋ฆฝํ•˜๋Š” ์–‘์˜ ์ƒ์ˆ˜ c์™€ N0๊ฐ€ ์กด์žฌํ•˜๋ฉด, f(N) = O(g(N)) f(N) = O(g(N))์€ N0 ๋ณด๋‹ค ํฐ ๋ชจ๋“  N ๋Œ€ํ•ด์„œ f(N)์ด ์–‘์˜ ์ƒ์ˆ˜๋ฅผ ๊ณฑํ•œ g(N)์— ๋ฏธ์น˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๋œป g(N)์€ f(N)์˜ ์ƒํ•œ(Upper Bound) ์ด๋ผ๊ณ  ํ•œ๋‹ค ฮฉ (Big-Omega) ํ‘œ๊ธฐ๋ฒ• ๋ชจ๋“  N โ‰ฅ N0์— ๋Œ€ํ•ด์„œ f(N) โ‰ฅ cg(N)์ด ์„ฑ๋ฆฝํ•˜๋Š” ์–‘์˜ ์ƒ์ˆ˜ c์™€ N0๊ฐ€ ์กด์žฌํ•˜๋ฉด, f(N) = ฮฉ(g(N)) f(N) = ฮฉ(g(N))์€ ์–‘์˜ ์ƒ์ˆ˜๋ฅผ ๊ณฑํ•œ g(N)์ด f(N)์— ๋ฏธ์น˜์ง€ ๋ชปํ•œ๋‹ค๋Š” ๋œป g(N)์„ f(N)์˜ ํ•˜ํ•œ(Lower Bound) ์ด๋ผ๊ณ  ํ•œ๋‹ค ฮ˜ (Theta) ํ‘œ๊ธฐ๋ฒ• ๋ชจ๋“  N โ‰ฅ N0์— ๋Œ€ํ•ด์„œ c1g(N) โ‰ฅ f(N) โ‰ฅ c2g(N)์ด ์„ฑ๋ฆฝํ•˜๋Š” ์–‘์˜ ์ƒ์ˆ˜ c1, c2, N0๊ฐ€ ์กด์žฌํ•˜๋ฉด, f(N) = ฮ˜(g(N)) ฮ˜-ํ‘œ๊ธฐ๋Š” ์ˆ˜ํ–‰์‹œ๊ฐ„์˜ O-ํ‘œ๊ธฐ์™€ ฮฉ-ํ‘œ๊ธฐ๊ฐ€ ๋™์ผํ•œ ๊ฒฝ์šฐ์— ์‚ฌ์šฉ ์ž์ฃผ ์‚ฌ์šฉ๋˜๋Š” ํ•จ์ˆ˜์˜ O-ํ‘œ๊ธฐ์™€ ์ด๋ฆ„ O(1), O(logN), O(N), O(NlogN), O(N2), O(N3), O(2N) 1-5 ์ˆœํ™˜ (Recursion) ์ˆœํ™˜์œผ๋กœ ๊ตฌํ˜„๋œ ๋ฉ”์†Œ๋“œ์˜ ๊ตฌ์„ฑ์š”์†Œ ๊ธฐ๋ณธ(Base) case : ์Šค์Šค๋กœ๋ฅผ ๋” ์ด์ƒ ํ˜ธ์ถœํ•˜์ง€ ์•Š๋Š” ๋ถ€๋ถ„ ์ˆœํ™˜ case : ์Šค์Šค๋กœ๋ฅผ ํ˜ธ์ถœํ•˜๋Š” ๋ถ€๋ถ„ ๊ผฌ๋ฆฌ ์ˆœํ™˜ (Tail Recursion) ๋ฉ”์†Œ๋“œ์˜ ๋งˆ์ง€๋ง‰ ๋ถ€๋ถ„์—์„œ ์ˆœํ™˜ (ํ˜ธ์ถœ ํ›„ ๋˜๋Œ์•„ ์™”์„๋•Œ ์ˆ˜ํ–‰ํ•  ์—ฐ์‚ฐ์ด ์—†๋Š” ๊ฒฝ์šฐ) ๊ผฌ๋ฆฌ ์ˆœํ™˜์€ ๋ฐ˜๋ณต๋ฌธ์œผ๋กœ ๋ณ€ํ™˜ํ•˜๋Š” ๊ฒƒ์ด ํšจ์œจ์ ์ด๋‹ค 1public class TailRecursion { 2 public static int factorial(int n, int fact) { 3 if (n==1) 4 return fact; 5 return factorial( ,); 6 } 7} ์ œ 2์žฅ : ๋ฆฌ์ŠคํŠธ ๋ฆฌ์ŠคํŠธ ์ผ๋ จ์˜ ๋™์ผํ•œ ํƒ€์ž…์˜ ํ•ญ๋ชฉ๋“ค์ด ๋‚˜์—ด๋œ ๊ฒƒ ๋ฐฐ์—ด ๋™์ผํ•œ ํƒ€์ž…์˜ ์›์†Œ๋“ค์ด ์—ฐ์†์ ์ธ ๋ฉ”๋ชจ๋ฆฌ ๊ณต๊ฐ„์— ํ• ๋‹น๋˜์–ด ๊ฐ ํ•ญ๋ชฉ์ด ํ•˜๋‚˜์˜ ์›์†Œ์— ์ €์žฅ๋˜๋Š” ๊ธฐ๋ณธ์ ์ธ ์ž๋ฃŒ๊ตฌ์กฐ ์ ‘๊ทผ : O(1), ์‚ฝ์ž…/์‚ญ์ œ : O(n) ๋ฐฐ์—ด๋กœ ๋ฆฌ์ŠคํŠธ ๊ตฌํ˜„ (ArrList) peek, insert, resize, delete ๋‹จ์ˆœ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ(Singly Linked List) print, search, insertFront, insertAfter ์ž๊ธฐ์ฐธ์กฐ๋ณ€์ˆ˜ 1public class Node <E> { 2 private Node<E> next; // ์ž๊ธฐ ์ฐธ์กฐ ๋ณ€์ˆ˜ 3 ... 4} ์ˆ˜ํ–‰์‹œ๊ฐ„ search : O(n) insert, delete : O(1), p๊ฐ€ ์•ˆ์ฃผ์–ด์ง€๋ฉด O(n) ์ด์ค‘ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ (Doubly Linked List) head, tail, item insertBefore, insertAfter, delete, ์ˆ˜ํ–‰์‹œ๊ฐ„ ์‚ฝ์ž…/์‚ญ์ œ ์—ฐ์‚ฐ : O(1) ํƒ์ƒ‰ ์—ฐ์‚ฐ : O(n) ์›ํ˜• ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ(Circular Linked List) ์ˆ˜ํ–‰์‹œ๊ฐ„ ์‚ฝ์ž…/์‚ญ์ œ ์—ฐ์‚ฐ : O(1) ํƒ์ƒ‰ ์—ฐ์‚ฐ : O(n) ์ œ 3์žฅ : ์Šคํƒ๊ณผ ํ ์Šคํƒ ๋ฐฐ์—ด๋กœ ๊ตฌํ˜„ / LinkedList๋กœ ๊ตฌํ˜„ ํ›„์œ„ ํ‘œ๊ธฐ <-> ์ค‘์œ„ ํ‘œ๊ธฐ ์ˆ˜ํ–‰์‹œ๊ฐ„ push, pop : O(1) ๋ฐฐ์—ด ํฌ๊ธฐ์˜ ํ™•๋Œ€/์ถ•์†Œ : O(n) ๋‹จ์ˆœ ์—ฐ๊ฒฐ ๋ฆฌ์ŠคํŠธ์˜ pop, push : O(1) ์ œ 4์žฅ : ํŠธ๋ฆฌ ์šฉ์–ด root, parent, child leaf, sibling, ancesto๋ฆฌ(์กฐ์ƒ), descendant(ํ›„์†) subtree(๋…ธ๋“œ ์ž์‹ ๊ณผ ํ›„์†์œผ๋กœ ๊ตฌ์„ฑ๋œ ํŠธ๋ฆฌ) degree(์ฐจ์ˆ˜ : ์ž์‹ ์ˆ˜) level (๊นŠ์ด์™€ ๋™์ผ, 0 ๋˜๋Š” 1๋ถ€ํ„ฐ ์‹œ์ž‘) height (ํŠธ๋ฆฌ์˜ ์ตœ๋Œ€ level) key (ํƒ์ƒ‰์— ์‚ฌ์šฉ๋˜๋Š” ๋…ธ๋“œ์— ์ €์žฅ๋œ ์ •๋ณด) ์™ผ์ชฝ ์ž์‹-์˜ค๋ฅธ์ชฝ ํ˜•์ œ (Left Child-Right Sibling) ํ‘œํ˜„ ๋…ธ๋“œ์˜ ์™ผ์ชฝ ์ž์‹๊ณผ ์˜ค๋ฅธ์ชฝ ํ˜•์ œ๋ฅผ ๊ฐ€๋ฆฌํ‚ค๋Š” 2๊ฐœ์˜ ๋ ˆํผ๋Ÿฐ์Šค๋งŒ ์‚ฌ์šฉ ์ด์ง„ ํŠธ๋ฆฌ (Binary Tree) ๊ฐ ๋…ธ๋“œ์˜ ์ž์‹ ์ˆ˜๊ฐ€ 2 ์ดํ•˜์ธ ํŠธ๋ฆฌ ํŠน๋ณ„ํ•œ ํ˜•ํƒœ์˜ ์ด์ง„ํŠธ๋ฆฌ ํฌํ™” ์ด์ง„ ํŠธ๋ฆฌ(Perfect Binary Tree) ๊ฐ ๋‚ด๋ถ€ ๋…ธ๋“œ๊ฐ€ 2๊ฐœ์˜ ์ž์‹์„ ๊ฐ€์ง€๊ณ  ๋ชจ๋“  ์ดํŒŒ๋ฆฌ๊ฐ€ ๊ฐ™์€ ์ธต์— ์žˆ๋Š” ํŠธ๋ฆฌ ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ(Complete Binary Tree) ๋งˆ์ง€๋ง‰ ๋ ˆ๋ฒจ์„ ์ œ์™ธํ•œ ๊ฐ ๋ ˆ๋ฒจ์ด ๋…ธ๋“œ๋“ค๋กœ ๊ฝ‰ ์ฐจ์žˆ๊ณ , ๋งˆ์ง€๋ง‰ ๋ ˆ๋ฒจ์—๋Š” ๋…ธ๋“œ๋“ค์ด ์™ผ์ชฝ๋ถ€ํ„ฐ ๋น ์ง์—†์ด ์ฑ„์›Œ์ง„ ํŠธ๋ฆฌ ์ด์ง„ ํŠธ๋ฆฌ์˜ ์†์„ฑ ๋ ˆ๋ฒจ k์— ์žˆ๋Š” ์ตœ๋Œ€ ๋…ธ๋“œ ์ˆ˜ = $2^{k-1}$ ๋†’์ด๊ฐ€ h์ธ ํฌํ™” ์ด์ง„ ํŠธ๋ฆฌ์— ์žˆ๋Š” ๋…ธ๋“œ ์ˆ˜ = $2^{h}-1$ n๊ฐœ์˜ ๋…ธ๋“œ๋ฅผ ๊ฐ€์ง„ ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ์˜ ๋†’์ด = $log_{2}(n+1)$ ๋†’์ด๊ฐ€ h์ธ ์™„์ „ ์ด์ง„ํŠธ๋ฆฌ์— ์กด์žฌํ•  ์ˆ˜ ์žˆ๋Š” ๋…ธ๋“œ ์ˆ˜ n ๋ฐฐ์—ด์— ์ €์žฅ๋œ ์ด์ง„ ํŠธ๋ฆฌ ํŠธ๋ฆฌ 1A 2โ”œโ”€โ”€ B 3โ”‚ โ”œ-โ”€ D 4โ”‚ โ”‚ โ”œโ”€โ”€ H 5โ”‚ โ”‚ โ””โ”€โ”€ I 6โ”‚ โ””-โ”€ E 7โ”‚ โ”œโ”€โ”€ J 8โ”‚ โ””โ”€โ”€ K 9โ””โ”€โ”€ C 10 โ”œโ”€โ”€ F 11 โ””โ”€โ”€ G ์œ„ ํŠธ๋ฆฌ๋ฅผ ๋ฐฐ์—ด์— ์ €์žฅํ•˜๋ฉด (์ธ๋ฑ์Šค 1๋ถ€ํ„ฐ ์‹œ์ž‘) 1A = [A, B, C, D, E, F, G, H, I, J, K] a[i]์˜ ๋ถ€๋ชจ๋Š” a[i/2], ๋‹จ i>1 a[i]์˜ ์™ผ์ชฝ ์ž์‹์€ a[2i], ๋‹จ 2i <= n a[i]์˜ ์˜ค๋ฅธ์ชฝ ์ž์‹์€ a[2i+1], ๋‹จ 2i+1 <= n ํŽธํ–ฅ(skewed) ์ด์ง„ ํŠธ๋ฆฌ ๋ฉ”๋ชจ๋ฆฌ ๋‚ญ๋น„๊ฐ€ ์‹ฌํ•˜๋‹ค ์ด์ง„ ํŠธ๋ฆฌ์˜ ์ˆœํšŒ preorder ; root - left - right inorder : left - root - right postorder : left - right - root levelorder : left -> right (from top level) ์ˆ˜ํ–‰ ์‹œ๊ฐ„ O(n) ์‹œ๊ฐ„์ด ์†Œ์š” ์ง‘ํ•ฉ์˜ ํ‘œํ˜„ ๋ฐฐ์—ด index 0 1 2 3 4 5 6 7 8 9 value 4 2 7 7 4 4 2 7 7 4 ์ง‘ํ•ฉ 1 17 2โ”œโ”€โ”€ 2 3โ”‚ โ”œ-โ”€ 1 4โ”‚ โ””-โ”€ 6 5โ”œโ”€โ”€ 8 6โ””โ”€โ”€ 3 ์ง‘ํ•ฉ2 14 2โ”œโ”€โ”€ 0 3โ”œโ”€โ”€ 5 4โ””โ”€โ”€ 9 ์ˆ˜ํ–‰ ์‹œ๊ฐ„ union : O(N) find : O(N) ์ œ 5์žฅ : ํƒ์ƒ‰ ํŠธ๋ฆฌ 5.1 ์ด์ง„ํƒ์ƒ‰ํŠธ๋ฆฌ min ํ•จ์ˆ˜ deleteMin ํ•จ์ˆ˜ delete ํ•จ์ˆ˜ CASE 1 : ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ๋‘ ์ž์‹์ด ๋ชจ๋‘ null CASE 2 : ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์˜ค๋ฅธ์ชฝ ์ž์‹๋งŒ null CASE 3 : ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์™ผ์ชฝ ์ž์‹๋งŒ null CASE 4 : ์‚ญ์ œํ•  ๋…ธ๋“œ์˜ ์ž์‹์ด ๋‘˜๋‹ค ์กด์žฌ ์‹œ๊ฐ„ ๋ณต์žก๋„ O($logn$) 5.2 AVL ํŠธ๋ฆฌ AVLํŠธ๋ฆฌ์˜ ์ •์˜ ์ž„์˜์˜ ๋…ธ๋“œ x์— ๋Œ€ํ•ด x์˜ ์™ผ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์™€ ์˜ค๋ฅธ์ชฝ ์„œ๋ธŒํŠธ๋ฆฌ์˜ ๋†’์ด ์ฐจ์ด๊ฐ€ 1์„ ๋„˜์ง€ ์•Š๋Š” ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ AVLํŠธ๋ฆฌ์˜ ํšŒ์ „ ์—ฐ์‚ฐ LL ํšŒ์ „ : ์™ผ์ชฝ์œผ๋กœ ์น˜์šฐ์นœ ๊ฒฝ์šฐ rotateRight(n)๋ฅผ ํ†ตํ•ด ํ•ด๊ฒฐ RR ํšŒ์ „ : ์˜ค๋ฅธ์ชฝ์œผ๋กœ ์น˜์šฐ์นœ ๊ฒฝ์šฐ rotateLeft(n)๋ฅผ ํ†ตํ•ด ํ•ด๊ฒฐ LR ํšŒ์ „ : rotateLeft(n.left) -> rotateRight(n)๋กœ ํ•ด๊ฒฐ RL ํšŒ์ „ : rotateRight(n.right) -> rotateLeft(n)๋กœ ํ•ด๊ฒฐ 4๊ฐ€์ง€ ํšŒ์ „์˜ ๊ณตํ†ต์  ํšŒ์ „ ํ›„์˜ ํŠธ๋ฆฌ๋“ค์ด ๋ชจ๋‘ ๊ฐ™๋‹ค, ๋ชจ๋‘ O(1) AVLํŠธ๋ฆฌ์˜ ์—ฐ์‚ฐ ์‚ฝ์ž… ์—ฐ์‚ฐ ์ด์ง„ ํŠธ๋ฆฌ์˜ ์‚ฝ์ž…๊ณผ ๋™์ผํ•˜๊ฒŒ ์ƒˆ ๋…ธ๋“œ ์‚ฝ์ž… ์ƒˆ ๋…ธ๋“œ๋กœ๋ถ€ํ„ฐ ๋ฃจํŠธ๋กœ ๊ฑฐ์Šฌ๋Ÿฌ ์˜ฌ๋ผ๊ฐ€๋ฉฐ ๋ถˆ๊ท ํ˜•์ด ๋ฐœ์ƒํ•˜๋ฉด ์ ์ ˆํ•˜๊ฒŒ ํšŒ์ „ ์—ฐ์‚ฐ ์ˆ˜ํ–‰ ์‚ญ์ œ ์—ฐ์‚ฐ 5.3 2-3 ํŠธ๋ฆฌ 2-3 ํŠธ๋ฆฌ์˜ ์ •์˜ ์ž„์˜์˜ ๋…ธ๋“œ๊ฐ€ 2๊ฐœ ๋˜๋Š” 3๊ฐœ์˜ ์ž์‹์„ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ํŠธ๋ฆฌ๋กœ, ๋ชจ๋“  ๋ฆฌํ”„ ๋…ธ๋“œ๊ฐ€ ๊ฐ™์€ ๋ ˆ๋ฒจ์— ์žˆ๋‹ค. 2-3 ํŠธ๋ฆฌ์˜ ์—ฐ์‚ฐ ํƒ์ƒ‰ ์—ฐ์‚ฐ ์ด์ง„ ํƒ์ƒ‰ ํŠธ๋ฆฌ์™€ ๋™์ผํ•œ ๋ฐฉ๋ฒ•์œผ๋กœ ํƒ์ƒ‰ ๋ถ„๋ฆฌ ์—ฐ์‚ฐ ํ‚ค๋ฅผ ๋ถ€๋ชจ๋กœ ์˜ฌ๋ ค ๋ณด๋ƒ„ ๋ถ€๋ชจ๊ฐ€ 3-๋…ธ๋“œ์ด๋ฉด ๋‹ค์‹œ ๋ถ„๋ฆฌ์—ฐ์‚ฐ ์ˆ˜ํ–‰ ๋ฃจํŠธ์—์„œ ์ผ์–ด๋‚˜๋ฉด ํŠธ๋ฆฌ์˜ ๋†’์ด 1 ์ฆ๊ฐ€ ์‚ฝ์ž… ์—ฐ์‚ฐ ์‚ฝ์ž… ํ›„ ๋ถ„๋ฆฌ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ ์‚ญ์ œ ์—ฐ์‚ฐ ์‚ญ์ œํ•  ๋…ธ๋“œ๊ฐ€ ์ดํŒŒ๋ฆฌ ๋…ธ๋“œ์ด๋ฉด ๊ทธ๋ƒฅ ์‚ญ์ œ ์‚ญ์ œํ•œ ๋…ธ๋“œ๊ฐ€ ์ดํŒŒ๋ฆฌ ๋…ธ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ๊ตํ™˜ ํ›„ ์‚ญ์ œ ์ด๋™ ์—ฐ์‚ฐ, ํ†ตํ•ฉ ์—ฐ์‚ฐ ์‚ฌ์šฉ ์ด๋™ ์—ฐ์‚ฐ ๋นˆ ์ž๋ฆฌ๋ฅผ ํ˜•์ œ์™€ ๋ฐ”๊พผ๋‹ค ์ด๋™์—ฐ์‚ฐ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด ํ†ตํ•ฉ ์—ฐ์‚ฐ ์ˆ˜ํ–‰ ํ†ตํ•ฉ ์—ฐ์‚ฐ ์‚ญ์ œํ•œ ๋…ธ๋“œ์˜ ๋ถ€๋ชจ์™€ ํ˜•์ œ๋ฅผ ํ†ตํ•ฉํ•œ๋‹ค 2-3 ํŠธ๋ฆฌ์˜ ์ˆ˜ํ–‰์‹œ๊ฐ„ ํƒ์ƒ‰, ์‚ฝ์ž…, ์‚ญ์ œ ์—ฐ์‚ฐ -> O($logn$) -> ํŠธ๋ฆฌ์˜ ๋†’์ด์— ๋น„๋ก€ ๋ถ„๋ฆฌ ์—ฐ์‚ฐ, ํ†ตํ•ฉ ์—ฐ์‚ฐ -> O(1) 2-3ํŠธ๋ฆฌ๊ฐ€ ๊ฐ€์žฅ ๋†’์€ ๊ฒฝ์šฐ ๋ชจ๋“  ๋…ธ๋‘๊ฐ€ 2-๋…ธ๋“œ์ธ ๊ฒฝ์šฐ ๋†’์ด : $ log_2(n+1) $ 2-3ํŠธ๋ฆฌ๊ฐ€ ๊ฐ€์žฅ ๋‚ฎ์€ ๊ฒฝ์šฐ ๋ชจ๋“  ๋…ธ๋“œ๊ฐ€ 3-๋…ธ๋“œ์ธ ๊ฒฝ์šฐ ๋†’์ด : $ log_3(n) $ 5.4 2-3-4 ํŠธ๋ฆฌ 2-3ํŠธ๋ฆฌ๋ฅผ ํ™•์žฅํ•œ 2-3-4 ํŠธ๋ฆฌ๋Š” ๋…ธ๋“œ๊ฐ€ ์ž์‹์„ 4๊ฐœ๊นŒ์ง€ ๊ฐ€์งˆ ์ˆ˜ ์žˆ๋Š” ์™„์ „๊ท ํ˜•ํŠธ๋ฆฌ ์ด๋ก ์ ์œผ๋กœ๋Š” 2-3ํŠธ๋ฆฌ์™€ ๋™์ผํ•˜๋‹ค ์‹ค์ œ๋กœ๋Š” ๋” ๋น ๋ฆ„ 5.5 B-ํŠธ๋ฆฌ B-ํŠธ๋ฆฌ์˜ ์ •์˜ ๋‹ค์ˆ˜์˜ ํ‚ค๋ฅผ ๊ฐ€์ง„ ๋…ธ๋“œ๋กœ ๊ตฌ์„ฑ๋˜์–ด ๋‹ค๋ฐฉํ–ฅ ํƒ์ƒ‰์ด ๊ฐ€๋Šฅํ•œ ๊ท ํ˜„ํŠธ๋ฆฌ B-ํŠธ๋ฆฌ์˜ ์—ฐ์‚ฐ ํƒ์ƒ‰ ์—ฐ์‚ฐ ๋ฃจํŠธ ๋ถ€ํ„ฐ ์‹œ์ž‘ ๊ฐ ๋…ธ๋“œ์—์„œ ์ด์ง„ ํƒ์ƒ‰ ์ˆ˜ํ–‰ ์‚ฝ์ž… ์—ฐ์‚ฐ ์ดํŒŒ๋ฆฌ์— ์ƒˆ ํ‚ค๋ฅผ ์ˆ˜์šฉํ•  ๊ณต๊ฐ„์ด ์žˆ๋‹ค๋ฉด, ์ •๋ ฌ๋œ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๋„๋ก ์‚ฝ์ž… ์ด๋ฏธ M-1๊ฐœ์˜ ํ‚ค๋ฅผ ๊ฐ€์ง€๊ณ  ์žˆ์œผ๋ฉด, ๋ถ„๋ฆฌ ์—ฐ์‚ฐ์„ ์ˆ˜ํ–‰ ์‚ญ์ œ ์—ฐ์‚ฐ ์‚ญ์ œํ•  ๋…ธ๋“œ๊ฐ€ ์ดํŒŒ๋ฆฌ ๋…ธ๋“œ์ด๋ฉด ๊ทธ๋ƒฅ ์‚ญ์ œ ์‚ญ์ œํ•œ ๋…ธ๋“œ๊ฐ€ ์ดํŒŒ๋ฆฌ ๋…ธ๋“œ๊ฐ€ ์•„๋‹ˆ๋ผ๋ฉด ๊ตํ™˜ ํ›„ ์‚ญ์ œ ์ด๋™ ์—ฐ์‚ฐ, ํ†ตํ•ฉ ์—ฐ์‚ฐ ์‚ฌ์šฉ ์ด๋™ ์—ฐ์‚ฐ ํ‚ค์˜ ์ˆ˜๊ฐ€ M/2-1๋ณด๋‹ค ์ž‘์œผ๋ฉด(underflow) ํ˜•์ œ, ๋ถ€๋ชจ๋…ธ๋“œ๋ฅผ ์ด๋Šฅ ์ด๋™ ์—ฐ์‚ฐ์ด ๋ถˆ๊ฐ€๋Šฅํ•˜๋ฉด ํ†ตํ•ฉ ์—ฐ์‚ฐ ์ˆ˜ํ–‰ ํ†ตํ•ฉ ์—ฐ์‚ฐ ์‚ญ์ œํ•œ ๋…ธ๋“œ์˜ ๋ถ€๋ชจ์™€ ํ˜•์ œ๋ฅผ ํ†ตํ•ฉํ•œ๋‹ค B-ํŠธ๋ฆฌ์˜ ์ˆ˜ํ–‰์‹œ๊ฐ„ ํƒ์ƒ‰, ์‚ฝ์ž…, ์‚ญ์ œ ์—ฐ์‚ฐ -> O($log_{M/2}n$) -> ํŠธ๋ฆฌ์˜ ๋†’์ด์— ๋น„๋ก€ ์ œ 6์žฅ : ํ•ด์‹œ ํ…Œ์ด๋ธ” ๋Œ€ํ‘œ์ ์ธ ํ•ด์‹œ ํ•จ์ˆ˜ ์ค‘๊ฐ„ ์ œ๊ณฑ ํ•จ์ˆ˜ : ํ‚ค๋ฅผ ์ œ๊ณฑํ•œ ํ›„, ์ ์ ˆํ•œ ํฌ๊ธฐ์˜ ์ค‘๊ฐ„ ๋ถ€๋ถ„์„ ์‚ฌ์šฉ ์ ‘๊ธฐ ํ•จ์ˆ˜ : ํ‚ค๋ฅผ ์—ฌ๋Ÿฌ ๋ถ€๋ถ„์œผ๋กœ ๋‚˜๋ˆˆ ํ›„, ์ด๋“ค์„ ๋”ํ•œ ๊ฐ’์„ ์‚ฌ์šฉ ์ž๋ฐ”์˜ hashCode() 1private int hash(Key k) { 2 return (k.hashCode() & 0x7fffffff) % M; 3} ํ•ด์‹œ ํ…Œ์ด๋ธ”์˜ ์ €์žฅ ๋ฐฉ์‹ ๊ฐœ๋ฐฉ ์ฃผ์†Œ ๋ฐฉ์‹ : ์ถฉ๋Œ๋œ ํ‚ค๋ฅผ ์ผ์ •ํ•œ ๋ฐฉ์‹์— ๋”ฐ๋ผ ์ฐพ์•„๋‚ธ empty์›์†Œ์— ์ €์žฅ ์„ ํ˜• ์กฐ์‚ฌ, ์ด์ฐจ์กฐ์‚ฌ, ์ด์ค‘ํ•ด์‹ฑ ์„ ํ˜• ์กฐ์‚ฌ : ์ถฉ๋Œ์ด ์ผ์–ด๋‚œ ๊ณณ์œผ๋กœ๋ถ€ํ„ฐ ์ˆœ์ฐจ์ ์œผ๋กœ ํƒ์ƒ‰ 1์ฐจ ๊ตฐ์ง‘ํ™” (ํ‚ค๋“ค์ด ๋ญ‰์ณ์ง€๋Š” ํ˜„์ƒ) ๋ฐœ์ƒ ๊ตฐ์ง‘ํ™”๋Š” ๊ตฐ์ง‘๋œ ํ‚ค๋“ค์„ ์ˆœ์ฐจ์ ์œผ๋กœ ๋ฐฉ๋ฌธํ•ด์•ผํ•˜๋Š” ๋ฌธ์ œ์ ์„ ์ผ์œผํ‚จ๋‹ค ์ œ 7์žฅ : ์šฐ์„ ์ˆœ์œ„ ํ ์šฐ์„ ์ˆœ์œ„ ํ (Priority Queue) ๊ฐ€์žฅ ๋†’์€ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„ ํ•ญ๋ชฉ์— ์ ‘๊ทผ๊ณผ ์‚ญ์ œ, ์ž„์˜์˜ ์šฐ์„ ์ˆœ์œ„๋ฅผ ๊ฐ€์ง„ ํ•ญ๋ชฉ์˜ ์‚ฝ์ž…์„ ์ง€์›ํ•˜๋Š” ์ž๋ฃŒ๊ตฌ์กฐ ํž™ (Heap) ์™„์ „ ์ด์ง„ ํŠธ๋ฆฌ๋กœ์„œ ๋ถ€๋ชจ์˜ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ์ž์‹์˜ ์šฐ์„ ์ˆœ์œ„๋ณด๋‹ค ๋†’์€ ์ž๋ฃŒ๊ตฌ์กฐ ์ตœ์†Œ ํž™, ์ตœ๋Œ€ ํž™ ํž™์˜ ์—ฐ์‚ฐ ์ตœ์†Ÿ๊ฐ’ ์‚ญ์ œ ๋ฃจํŠธ ์‚ญ์ œ ํ›„, ๋งˆ์ง€๋ง‰ ๋…ธ๋“œ๋ฅผ ๋ฃจํŠธ๋กœ ์ด๋™ downheap ์ˆ˜ํ–‰ : ๋ฃจํŠธ๋ถ€ํ„ฐ ๋น„๊ตํ•˜๋ฉด์„œ ๋‚ด๋ ค๊ฐ ์‚ฝ์ž… ๋งˆ์ง€๋ง‰ ํ•ญ๋ชฉ์˜ ๋‹ค์Œ์— ์‚ฝ์ž… upheap ์ˆ˜ํ–‰ : ๋ฃจํŠธ๋กœ ๋น„๊ตํ•˜๋ฉด์„œ ์˜ฌ๋ผ๊ฐ ์ƒํ–ฅ์‹ ํž™ 1public void createHeap() { 2 for (int i = N/2; i>0; i--) { 3 downheap(i); 4 } 5} O(n) ์ˆ˜ํ–‰ ์‹œ๊ฐ„ ์ ‘๊ทผ, ์‚ฝ์ž…, ์‚ญ์ œ : O(logn) ์ œ 8์žฅ : ์ •๋ ฌ ์„ ํƒ ์ •๋ ฌ (Selection Sort) ํ•ญ์ƒ O(n^2) ์‚ฝ์ž… ์ •๋ ฌ (Insertion Sort) ์ตœ์•… : O(n^2) ์ตœ์„  : O(n) : ์ด๋ฏธ ์ •๋ ฌ๋œ ๊ฒฝ์šฐ ํž™ ์ •๋ ฌ (Heap Sort) ํ•ญ์ƒ : O(nlogn) ํ•ฉ๋ณ‘ ์ •๋ ฌ (Merge Sort) ํ•ญ์ƒ : O(nlogn) Stable Sort : ๊ฐ™์€ ๊ฐ’์˜ ํ‚ค๋ฅผ ๊ฐ€์ง„ ๋ ˆ์ฝ”๋“œ์˜ ์ˆœ์„œ๊ฐ€ ์ •๋ ฌ ํ›„์—๋„ ์œ ์ง€๋˜๋Š” ์ •๋ ฌ ํ€ต ์ •๋ ฌ (Quick Sort) ์ตœ์•… : O(n^2) ์ตœ์„  : O(nlogn) ์„ฑ๋Šฅ ํ–ฅ์ƒ ๋ฐฉ๋ฒ• Median of Three : ์ฒซ๋ฒˆ์งธ, ๋งˆ์ง€๋ง‰, ์ค‘๊ฐ„๊ฐ’ ์ค‘์—์„œ ์ค‘๊ฐ„๊ฐ’์„ ํ”ผ๋ฒ—์œผ๋กœ ์„ ํƒ ์ž…๋ ฅ์ด ์ž‘์€ ํฌ๊ธฐ๊ฐ€ ๋˜์—ˆ์„๋•Œ ์‚ฝ์ž… ์ •๋ ฌ์„ ์‚ฌ์šฉ
new ์›น ๋ณด์•ˆ
๐Ÿซ ํ•™๊ณผ ๊ณต๋ถ€
Web Security Model Web ๋ณด์•ˆ์˜ ๋ชฉํ‘œ Integirty : ๋ฌด๊ฒฐ์„ฑ Confidentiality : ๊ธฐ๋ฐ€์„ฑ HTTP URL https:// www.example.edu :80 /lectures ?lec=80 #slides protocol + hostname + port + path + query + fragment Cookies ์„œ๋ฒ„๊ฐ€ ์›น ๋ธŒ๋ผ์šฐ์ €์—๊ฒŒ ๋ณด๋‚ด๋Š” ์ •๋ณด ์—ญํ•  : ์„ธ์…˜ ๊ด€๋ฆฌ, ์‚ฌ์šฉ์ž ์„ค์ • ์ €์žฅ, ์‚ฌ์šฉ์ž ์ถ”์  ๋“ฑ 1// ์ฟ ํ‚ค ์„ค์ • 2Set-Cookie: name=value; 3// ์ฟ ํ‚ค ์ „์†ก 4Cookie: name=value; Same Origin Policy (SOP) ๊ฐ™์€ Origin์—์„œ๋งŒ ๋ฆฌ์†Œ์Šค๋ฅผ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•œ๋‹ค Origin scheme://domain:port Domain Relaxation ์„œ๋ธŒ ๋„๋ฉ”์ธ ๊ฐ„์˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ  document.domain์„ ์ˆ˜์ •ํ•˜์—ฌ, ์„œ๋ธŒ ๋„๋ฉ”์ธ ๊ฐ„์˜ ๋ฆฌ์†Œ์Šค ๊ณต์œ  ๊ฐ€๋Šฅ ์˜ˆ์‹œ 1a.domain.com -> domain.com ๊ฐ€๋Šฅ 2a.domain.com -> b.domain.com ๋ถˆ๊ฐ€๋Šฅ 3a.domain.com -> com ๋ถˆ๊ฐ€๋Šฅ ์ทจ์•ฝ์  : ์•…์˜์ ์ธ ์‚ฌ์ดํŠธ๊ฐ€ document.domain์„ ์ˆ˜์ •ํ•˜์—ฌ ์ ‘๊ทผ์„ ์‹œ๋„ํ•  ์ˆ˜ ์žˆ์Œ ํ•ด๊ฒฐ๋ฐฉ๋ฒ• : Mozilla Public Suffix List (PSL) ์‚ฌ์šฉ BroadcastChannel API ๊ฐ™์€ origin์˜ ๋‹ค๋ฅธ context ๊ฐ„์˜ ํ†ต์‹  ์‚ฌ์šฉ๋ฒ• 1const bc = new BroadcastChannel('channel'); 2bc.postMessage('message'); 3bc.onmessage = (e) => console.log(e.data); XMLHttpRequest (XHR) ์„œ๋ฒ„์™€ ๋น„๋™๊ธฐ ํ†ต์‹ ์„ ์œ„ํ•œ ๊ฐ์ฒด CORS (Cross-Origin Resource Sharing) ๋‹ค๋ฅธ Origin์˜ ๋ฆฌ์†Œ์Šค๋ฅผ ์š”์ฒญํ•  ๋•Œ, ์„œ๋ฒ„์—์„œ ํ—ˆ์šฉํ•˜๋Š” ์ •์ฑ… Cookie ์„œ๋ฒ„๊ฐ€ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ณด๋‚ด๋Š” ์ •๋ณด Cookie Scoping Domain ํ•ด๋‹น ๋„๋ฉ”์ธ์€ Subdomain ๋˜๋Š” Parent Domain์— ๋Œ€ํ•ด์„œ๋งŒ ์ฟ ํ‚ค๋ฅผ ์ „์†ก Path ํ•ด๋‹น ๊ฒฝ๋กœ์˜ ํ•˜์œ„ ๊ฒฝ๋กœ๊นŒ์ง€ ์ฟ ํ‚ค๋ฅผ ์ „์†ก Secure Cookies HTTPS ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•  ๋•Œ๋งŒ ์ฟ ํ‚ค๋ฅผ ์ „์†ก 1Set-Cookie: name=value; Secure HTTPOnly Cookies JavaScript์—์„œ ์ฟ ํ‚ค์— ์ ‘๊ทผํ•  ์ˆ˜ ์—†๋„๋ก ํ•จ 1Set-Cookie: name=value; HttpOnly CSRF (Cross Site Request Forgery) ๋‹ค๋ฅธ ์‚ฌ์ดํŠธ์—์„œ ์š”์ฒญ์„ ์œ„์กฐํ•˜์—ฌ ๊ณต๊ฒฉํ•˜๋Š” ๊ธฐ๋ฒ• ๋ฐฐ๊ฒฝ ํŠน์ • ์‚ฌ์šฉ์ž๊ฐ€ ๋กœ๊ทธ์ธ๋œ ์ƒํƒœ๋ผ๋ฉด, ์‚ฌ์šฉ์ž๋ฅผ ํ™•์ธํ•˜๊ธฐ ์œ„ํ•ด ๋ธŒ๋ผ์šฐ์ €์—์„œ ์ฟ ํ‚ค์™€ ํ•จ๊ป˜ ์š”์ฒญ์„ ์ „์†ก cross-site์—์„œ๋„ ์ฟ ํ‚ค์™€ ํ•จ๊ป˜ ์š”์ฒญ์„ ๋ณด๋ƒˆ์„๋•Œ, ์„œ๋ฒ„๊ฐ€ same-site์ธ์ง€ cross-site์ธ์ง€ ํ™•์ธ์ด ๋ถˆ๊ฐ€ํ•œ ๊ฒฝ์šฐ CSRF ๊ณต๊ฒฉ ๊ฐ€๋Šฅ ์˜ˆ์ƒ ์‹œ๋‚˜๋ฆฌ์˜ค ํ”ผํ•ด์ž๊ฐ€ ํ˜„์žฌ ๋กœ๊ทธ์ธ๋œ ์ƒํƒœ๋กœ Malicious Site์— ์ ‘์† Malicious site์—์„œ ํ”ผํ•ด์ž ์˜์ง€์™€ ์ƒ๊ด€์—†์ด ์ฟ ํ‚ค์™€ ํ•จ๊ป˜ ์š”์ฒญ์„ ์ „์†ก GET ์˜ˆ์‹œ ์ฝ”๋“œ 1<img src="http://bank.com/transfer?to=attacker&amount=1000" /> POST ์˜ˆ์‹œ ์ฝ”๋“œ 1<form action="http://bank.com/transfer" method="post"> 2 <input type="hidden" name="to" value="attacker" /> 3 <input type="hidden" name="amount" value="1000" /> 4</form> 5<script> 6 document.forms[0].submit(); 7</script> ๋ฐฉ์–ด Referer Header ์š”์ฒญ์„ ๋ณด๋‚ธ ํŽ˜์ด์ง€์˜ ์ฃผ์†Œ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” HTTP header๋ฅผ ํ™•์ธํ•˜์—ฌ, ์š”์ฒญ์„ ๋ณด๋‚ธ ํŽ˜์ด์ง€๊ฐ€ ๊ฐ™์€ ์‚ฌ์ดํŠธ์ธ์ง€ ํ™•์ธ 1Referer: http://www.example.com ํ•œ๊ณ„ ํ•ด๋‹น field๋ฅผ ์ด์šฉํ•ด์„œ ์ ‘์† ๊ธฐ๋ก์„ ํ™•์ธ ๊ฐ€๋Šฅ -> ๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ ๋ฌธ์ œ Same-Site Cookies ์„œ๋ฒ„๊ฐ€ ์ฟ ํ‚ค๋ฅผ ์ „์†กํ•  ๋•Œ, SameSite๋ผ๋Š” ์ฟ ํ‚ค ์†์„ฑ๋ฅผ ์ „์†ก, same-site์ธ์ง€ cross-site์ธ์ง€ ํ™•์ธํ•˜์—ฌ, ์„ค์ •๊ฐ’์— ๋”ฐ๋ผ ์ฟ ํ‚ค๋ฅผ ์ „์†กํ•˜์ง€ ์•Š์Œ ์„ค์ • ๊ฐ’ None (๋ชจ๋“  ์š”์ฒญ์— ์ฟ ํ‚ค ์ „์†ก) Strict (cross-site๋Š” ํ•ญ์ƒ ์ฟ ํ‚ค ์ „์†กํ•˜์ง€ ์•Š์Œ) Lax (cross-site๋Š” GET ์š”์ฒญ์‹œ์—๋งŒ ์ฟ ํ‚ค ์ „์†กํ•˜์ง€ ์•Š์Œ) Secret Token ํŠน์ • origin์˜ ์ฒซ ์š”์ฒญ๋•Œ, ํŠน์ •ํ•œ ํ† ํฐ์„ ์ƒ์„ฑ, ์ดํ›„ ์š”์ฒญ์‹œ ํ•ด๋‹น ํ† ํฐ์„ ํ•จ๊ป˜ ์ „์†กํ•˜์—ฌ, ์š”์ฒญ์ด ๊ฐ™์€ Origin์—์„œ ์˜จ ๊ฒƒ์ธ์ง€ ํ™•์ธ Bypassing with Clickjacking ์‚ฌ์šฉ์ž๊ฐ€ ์˜๋„ํ•˜์ง€ ์•Š์€ ํด๋ฆญ์„ ์œ ๋„ํ•˜์—ฌ, CSRF ๊ณต๊ฒฉ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ธฐ๋ฒ• ๋ฐฉ์–ด X-Frame-Options Header (๊ฐ’ : DENY, SAMEORIGIN, ALLOW-FROM uri) ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ iframe์œผ๋กœ ๋ Œ๋”๋งํ•˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ XSS(Cross Site Scripting) Attack Non-persistent (Reflected) XSS Attack ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ๊ฐ’์„ ๊ทธ๋Œ€๋กœ ์ถœ๋ ฅํ•˜์—ฌ, ๊ณต๊ฒฉ์ž๊ฐ€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฝ์ž…ํ•˜์—ฌ ๊ณต๊ฒฉํ•˜๋Š” ๊ธฐ๋ฒ• ์˜ˆ์‹œ query string์„ ์‹คํ–‰ํ•˜๋Š” ํŽ˜์ด์ง€๊ฐ€ ์กด์žฌ (innerHTML) ํ”ผํ•ด์ž๊ฐ€ ํ•ด๋‹น ๋งํฌ๋ฅผ ์‹คํ–‰ => http://www.example.com/search?input=<script>alert(โ€œattackโ€);</script> ํ”ผํ•ด์ž์˜ ๋ธŒ๋ผ์šฐ์ €์—์„œ alert๊ฐ€ ์‹คํ–‰๋จ Persistent (Stored) XSS Attack ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ๊ฐ’์„ DB์— ์ €์žฅํ•˜์—ฌ, ๊ณต๊ฒฉ์ž๊ฐ€ ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฝ์ž…ํ•˜์—ฌ ๊ณต๊ฒฉํ•˜๋Š” ๊ธฐ๋ฒ• ์˜ˆ์‹œ ๊ฒŒ์‹œํŒ์— ๊ธ€์„ ์ž‘์„ฑํ•˜๋Š” ํŽ˜์ด์ง€๊ฐ€ ์กด์žฌ ํ”ผํ•ด์ž๊ฐ€ ํ•ด๋‹น ํŽ˜์ด์ง€์— ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‚ฝ์ž…ํ•˜์—ฌ ๊ธ€์„ ์ž‘์„ฑ ๋‹ค๋ฅธ ์‚ฌ์šฉ์ž๊ฐ€ ํ•ด๋‹น ๊ธ€์„ ์ฝ์„ ๋•Œ, ์Šคํฌ๋ฆฝํŠธ๊ฐ€ ์‹คํ–‰๋จ XSS๋กœ ๋ฐœ์ƒ ๊ฐ€๋Šฅํ•œ ํ”ผํ•ด Web defacing(์›นํŽ˜์ด์ง€ ๋ณ€์กฐ) Spoofing requests(์‚ฌ์šฉ์ž์˜ ์š”์ฒญ ๋ณ€์กฐ) Stealing information(์ •๋ณด ํƒˆ์ทจ) Self-Propagation XSS Worm XSS ๊ณต๊ฒฉ์„ ํ†ตํ•ด, ์ž๋™์œผ๋กœ ๊ณต๊ฒฉ์„ ์ „ํŒŒํ•˜๋Š” ๊ธฐ๋ฒ• 2๊ฐ€์ง€ ์ ‘๊ทผ DOM Approach 1let jsCode = document.getElementById('worm').innerHTML; Link Approach 1let jsCode = `'<script src="http://www.example.com/worm.js"></script>'`; ๋ฐฉ์–ด ์ž…๋ ฅ๊ฐ’ ํ•„ํ„ฐ๋ง : ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ๊ฐ’์„ ํ•„ํ„ฐ๋งํ•˜์—ฌ, ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๋„๋ก ํ•œ๋‹ค Encoding : ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ๊ฐ’์„ ์ถœ๋ ฅํ•  ๋•Œ, HTML Encodingํ•˜์—ฌ, ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๋„๋ก ํ•œ๋‹ค Content Security Policy (CSP) : ์›นํŽ˜์ด์ง€์—์„œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ œํ•œํ•˜์—ฌ, XSS ๊ณต๊ฒฉ์„ ๋ฐฉ์–ดํ•œ๋‹ค ์˜ˆ์‹œ (script ํŒŒ์ผ) 1Content-Security-Policy: script-src 'self' example.com ์˜ˆ์‹œ (inline script) 1Content-Security-Policy: script-src 'nonce-2726c7f26c' 2// allowed script 3`<script nonce=2726c7f26c> ... </script>` 4// not allowed script 5`<script nonce=42eh44jhad> ... </script>` SQL Injection SQL ์ฟผ๋ฆฌ๋ฅผ ์กฐ์ž‘ํ•˜์—ฌ, DB์— ๋Œ€ํ•œ ๊ณต๊ฒฉ์„ ์ˆ˜ํ–‰ํ•˜๋Š” ๊ธฐ๋ฒ• ์˜ˆ์‹œ EID์— “EID5002’#“์„ ์‚ฝ์ž… -> PASSWORD ๊ฒ€์ฆ์„ ์šฐ์ฆ 1SELECT NAME, SALERY, SSN 2FROM EMPLOYEE 3WHERE EID='EID5002'#' AND PASSWORD='1234'; curl์„ ์ด์šฉํ•ด์„œ SQL Injection ๊ณต๊ฒฉ 1curl 'www.example.com/getdata.php?EID=a' OR 1=1&PASSWORD=' ๋ฐฉ์–ด Filtering and Encoding data SQL Injection์—์„œ ์“ฐ์ด๋Š” ํŠน์ˆ˜๋ฌธ์ž๋ฅผ Filtering, Encoding 1$mysqli->real_escape_string($input); ํ•œ๊ณ„ ํ•„์š”ํ•œ ๋ฌธ์ž์—ด์„ ํ•„ํ„ฐ๋งํ•  ์ˆ˜ ์žˆ์Œ Prepared Statements SQL ์ฟผ๋ฆฌ๋ฅผ ๋ฏธ๋ฆฌ ์ค€๋น„ํ•˜์—ฌ, ์‚ฌ์šฉ์ž์˜ ์ž…๋ ฅ๊ฐ’์„ ์‚ฝ์ž…ํ•˜์ง€ ์•Š๊ณ , ์ฟผ๋ฆฌ๋ฅผ ์‹คํ–‰ 1$stmt = $mysqli->prepare("SELECT NAME, SALARY, SSN FROM EMPLOYEE WHERE EID=? AND PASSWORD=?"); 2// ss means "string string" 3$stmt->bind_param("ss", $EID, $PASSWORD); 4$stmt->execute(); Blind SQL Injection SQL Injection ๊ณต๊ฒฉ์„ ํ†ตํ•ด, DB์— ๋Œ€ํ•œ ์ •๋ณด๋ฅผ ํƒˆ์ทจํ•˜๋Š” ๊ธฐ๋ฒ• Conditional Response 1/* Password์˜ ์ฒซ๋ฒˆ์งธ ๋ฌธ์ž๊ฐ€ 'm'๋ณด๋‹ค ํฐ์ง€ ํ™•์ธ */ 2xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 'm 3/* Password์˜ ์ฒซ๋ฒˆ์งธ ๋ฌธ์ž๊ฐ€ 't'๋ณด๋‹ค ํฐ์ง€ ํ™•์ธ */ 4xyz' AND SUBSTRING((SELECT Password FROM Users WHERE Username = 'Administrator'), 1, 1) > 't SQL Error - Divide by Zero 1/* Password์˜ ์ฒซ๋ฒˆ์งธ ๋ฌธ์ž๊ฐ€ 'm'๋ณด๋‹ค ํฌ๋ฉด ์˜ค๋ฅ˜ ๋ฐœ์ƒ */ 2xyz' AND (SELECT CASE WHEN (Username = 'Administrator' AND SUBSTRING(Password, 1, 1) > 3'm') THEN 1/0 ELSE 'a' END FROM Users)='a SQL Error - Cast 1/* Password์˜ ์ฒซ๋ฒˆ์งธ ๋ฌธ์ž๊ฐ€ 'm'๋ณด๋‹ค ํฌ๋ฉด ์˜ค๋ฅ˜ ๋ฐœ์ƒ */ 2CAST((SELECT example_column FROM example_table) AS int) Time Delay 1/* Password์˜ ์ฒซ๋ฒˆ์งธ ๋ฌธ์ž๊ฐ€ 'm'๋ณด๋‹ค ํฌ๋ฉด ๋”œ๋ ˆ์ด ๋ฐœ์ƒ */ 2'; IF (SELECT COUNT(Username) FROM Users WHERE Username = 'Administrator' AND 3SUBSTRING(Password, 1, 1) > 'm') = 1 WAITFOR DELAY '0:0:{delay}'- ShellShock Attack bash ์‰˜์˜ ์ทจ์•ฝ์ ์„ ์ด์šฉํ•˜์—ฌ, ๊ณต๊ฒฉํ•˜๋Š” ๊ธฐ๋ฒ• Set-UID Programs Set-UID root ๊ถŒํ•œ์„ ๊ฐ€์ง„ ํ”„๋กœ๊ทธ๋žจ์ด systemํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•  ๋•Œ, ๊ณต๊ฒฉํ•˜๋Š” ๊ธฐ๋ฒ• RUID : Real User ID : ํ”„๋กœ๊ทธ๋žจ์„ ์‹คํ–‰ํ•œ ์‚ฌ์šฉ์ž์˜ ๊ถŒํ•œ EUID : Effective User ID : ํ”„๋กœ๊ทธ๋žจ์ด ์‹คํ–‰๋˜๋Š” ๊ถŒํ•œ Set-UID Program : ์‚ฌ์šฉ์ž๊ฐ€ ํ”„๋กœ๊ทธ๋žจ์„ root ๊ถŒํ•œ์œผ๋กœ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ, RUID์™€ EUID๊ฐ€ ๋‹ค๋ฆ„, Set-UID Program์„ ๋งŒ๋“œ๋Š” ๋ฐฉ๋ฒ• 1$ sudo chown root vul 2$ sudo chmod 4755 vul 3$ ls -l vul 4-rwsr-xr-x 1 root root 1234 Mar 11 12:00 vul # s๊ฐ€ ์กด์žฌ ์ทจ์•ฝํ•œ C ํ”„๋กœ๊ทธ๋žจ (vul : Set-UID program) 1#include <stdio.h> 2void main() { 3 setuid(geteuid()); // root ๊ถŒํ•œ์„ ๊ฐ€์ง„ ์‚ฌ์šฉ์ž๋กœ ์„ค์ • 4 system("/bin/ls -l"); // ls -l ๋ช…๋ น์–ด ์‹คํ–‰ 5} ๊ณต๊ฒฉ ๋ช…๋ น์–ด 1$ export foo='() { echo "hello"; }; /bin/sh' 2$ ./vul CGI(Common Gateway Interface) Programs ์›น ์„œ๋ฒ„์—์„œ ์‚ฌ์šฉํ•˜๋Š” CGI ํ”„๋กœ๊ทธ๋žจ์— ๋Œ€ํ•œ ์ทจ์•ฝ์  ์ทจ์•ฝํ•œ CGI ํ”„๋กœ๊ทธ๋žจ (test.cgi) 1#!/bin/bash 2echo "Content-type: text/plain" 3echo 4echo "Hello, World!" ๊ณต๊ฒฉ ๋ช…๋ น์–ด 1$ curl http://10.0.2.69/cgi-bin/test.cgi 2Hello, World! ๊ณต๊ฒฉ์„ ํ™œ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ• ์„ค์ • ํŒŒ์ผ์— ํ•˜๋“œ์ฝ”๋”ฉ๋œ db password ํƒˆ์ทจ reverse shell ์‹คํ–‰ Environment Variables & Attacks ํ”„๋กœ์„ธ์Šค๊ฐ€ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์–ป๋Š” ๋ฐฉ๋ฒ• fork() : ์ž์‹์„ ์ƒ์„ฑ, ์ž์‹์ด ๋ถ€๋ชจ์˜ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์ƒ์† execve() : ์ƒˆ๋กœ์šด ํ”„๋กœ๊ทธ๋žจ์„ ์ž์‹์œผ๋กœ ์‹คํ–‰, ์ƒˆ๋กœ ํ™˜๊ฒฝ๋ณ€์ˆ˜๋ฅผ ์„ค์ • Attacks via Dynamic Linker ๋งํฌ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์กฐ์ž‘ํ•˜์—ฌ, ๊ณต๊ฒฉํ•˜๋Š” ๊ธฐ๋ฒ• ์›๋ฆฌ LD_PRELOAD๋Š” ๊ณต์œ  ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์˜ ๋ชฉ๋ก์„ ์ €์žฅ ํ•จ์ˆ˜๋ฅผ ์ฐพ์ง€ ๋ชปํ•˜๋ฉด, LD_LIBRARY_PATH์—์„œ ์ฐพ์Œ ๋‘ ๋ณ€์ˆ˜๋ฅผ ์กฐ์ž‘ํ•˜์—ฌ ๋งํฌ๋œ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์กฐ์ž‘ ์˜ˆ์‹œ 1$ export LD_PRELOAD=/path/to/malicious.so 2$ ./vul Attacks via Execution Program ์‹คํ–‰ ํ”„๋กœ๊ทธ๋žจ์„ ์กฐ์ž‘ํ•˜์—ฌ, ๊ณต๊ฒฉํ•˜๋Š” ๊ธฐ๋ฒ• ์˜ˆ์‹œ 1$ export PATH=/path/to/malicious:$PATH 2$ ./vul 3# // root shell ์ทจ๋“ Attacks via Library format string ๋“ฑ์˜ ์ทจ์•ฝ์ ์„ ์ด์šฉํ•˜์—ฌ ๊ณต๊ฒฉํ•˜๋Š” ๊ธฐ๋ฒ• Attacks via Application Code buffer overflow ๋“ฑ์˜ ์ทจ์•ฝ์ ์„ ์ด์šฉํ•˜์—ฌ ๊ณต๊ฒฉํ•˜๋Š” ๊ธฐ๋ฒ• Set-UID Approach VS Service Approach Clickjacking Attack ์‚ฌ์šฉ์ž์˜ ์˜๋„์™€ ์ƒ๊ด€์—†์ด ํด๋ฆญ์„ ์œ ๋„ํ•˜์—ฌ, ๊ณต๊ฒฉํ•˜๋Š” ๊ธฐ๋ฒ• 1<iframe id="top" src="http://www.attack.com" style="opacity: 0"></iframe> 2<iframe id="bottom" src="http://www.example.com>" style="opacity: 1"></iframe> ๋ฐฉ์–ด Client-side (Framekiller and Framebuster) javascript๋ฅผ ์ด์šฉํ•˜์—ฌ, ํ•ด๋‹น ํŽ˜์ด์ง€๊ฐ€ iframe์œผ๋กœ ๋ Œ๋”๋ง๋˜๋Š” ๊ฒƒ์„ ๋ฐฉ์ง€ 1if (top != self) 2if (top.location != self.location) 3... ํ•œ๊ณ„ ์šฐํšŒํ•  ์ˆ˜ ์žˆ๋Š” ๋ฐฉ๋ฒ•์ด ๋งŽ์•„์„œ ๋ถˆ์•ˆ์ • -> ์ž˜ ์“ฐ์ง€ ์•Š๋Š”๋‹ค ์šฐํšŒ Double framing : ๋‘๊ฐœ์˜ iframe์„ ์‚ฌ์šฉํ•˜์—ฌ, ์ฒซ๋ฒˆ์งธ iframe์„ ์ˆจ๊ธฐ๊ณ , ๋‘๋ฒˆ์งธ iframe์„ ๋ณด์—ฌ์คŒ Abusing onBeforeUnload : ์‚ฌ์šฉ์ž๊ฐ€ ํŽ˜์ด์ง€๋ฅผ ๋– ๋‚  ๋•Œ, alert์„ ๋„์›Œ์„œ, ์‚ฌ์šฉ์ž์˜ ํด๋ฆญ์„ ์œ ๋„ sandbox attribute : iframe์— sandbox attribute๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ํ•ด๋‹น iframe์—์„œ๋Š” ์Šคํฌ๋ฆฝํŠธ๋ฅผ ์‹คํ–‰ํ•˜์ง€ ์•Š๋„๋ก ํ•จ options allow-same-origin allow-scripts allow-forms allow-modals allow-top-navigation ์˜ˆ์‹œ 1<iframe ... sandbox="allow_forms allow-scripts"></iframe> Referrer checking problems Referer๋ฅผ ํ™•์ธํ•˜์—ฌ ํŠน์ • ๋„๋ฉ”์ธ์˜ ์‚ฌ์ดํŠธ๋งŒ iframe์œผ๋กœ ๋ Œ๋”๋ง๋˜์—ˆ๋Š”์ง€ ํ™•์ธ ํ•œ๊ณ„ : Referer๋ฅผ ์กฐ์ž‘ํ•˜์—ฌ ์šฐํšŒ ๊ฐ€๋Šฅ Server-side X-Frame-Options ํŠน์ • ORIGIN ํŽ˜์ด์ง€์—์„œ๋งŒ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ iframe์œผ๋กœ ๋ Œ๋”๋งํ•  ์ˆ˜ ์žˆ๋„๋ก ํ•จ ์˜ˆ์‹œ 1X-Frame-Options: DENY // ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ iframe์œผ๋กœ ๋ Œ๋”๋งํ•˜์ง€ ์•Š์Œ 2X-Frame-Options: SAMEORIGIN // ๊ฐ™์€ ORIGIN ํŽ˜์ด์ง€์—์„œ๋งŒ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ iframe์œผ๋กœ ๋ Œ๋”๋ง 3X-Frame-Options: ALLOW-FROM uri // ํŠน์ • uri์—์„œ๋งŒ ํ•ด๋‹น ํŽ˜์ด์ง€๋ฅผ iframe์œผ๋กœ ๋ Œ๋”๋ง Outdated : CSP ์‚ฌ์šฉ ๊ถŒ์žฅ Content Security Policy (CSP) ์›นํŽ˜์ด์ง€์—์„œ ์‹คํ–‰ ๊ฐ€๋Šฅํ•œ ๋ฆฌ์†Œ์Šค๋ฅผ ์ œํ•œ script-src : ์Šคํฌ๋ฆฝํŠธ source๋ฅผ ์ œํ•œ img-src : ์ด๋ฏธ์ง€์˜ source๋ฅผ ์ œํ•œ frame-ancestors : <frame>, <iframe>, <object>, <embed> ๋˜๋Š” <applet> ์š”์†Œ์˜ ๋ถ€๋ชจ๋ฅผ ์ œํ•œ ์˜ˆ์‹œ 1$csp = "Content-Security-Policy: frame-ancestors *"; 2header($csp); Types of Context Integrity Visual Integrity ๋ณด์ด๋Š” ๊ฒƒ๊ณผ ์‹ค์ œ๋กœ ์‹คํ–‰๋˜๋Š” ๊ฒƒ์˜ ์ฐจ์ด์— ๋Œ€ํ•œ ๋ฌด๊ฒฐ์„ฑ ๋ฐฉ์–ด๋ฅผ ์œ„ํ•œ ๋ฐฉ๋ฒ• : User Confirmation, UI Randomization, Visibility Detection on Click Temporary Integrity ์‚ฌ์šฉ์ž ํ™•์ธ ์‹œ์ ๊ณผ ํด๋ฆญ ์‹œ์ž‘ ์‹œ์  ์‚ฌ์ด์˜ UI ์ƒํƒœ ์ฐจ์ด์— ๋Œ€ํ•œ ๋ฌด๊ฒฐ์„ฑ ๋ฐฉ์–ด๋ฅผ ์œ„ํ•œ ๋ฐฉ๋ฒ• : Access Control Gadgets SSRF (Server Side Request Forgery) ์„œ๋ฒ„์—์„œ ๋‹ค๋ฅธ ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ณต๊ฒฉ ๊ธฐ๋ฒ• ๊ณต๊ฒฉ (์„œ๋ฒ„๊ฐ€ ์‹ ๋ขฐ๋œ ์„œ๋ฒ„์—์„œ ์š”์ฒญ์ด ์˜จ ๊ฒƒ์œผ๋กœ ์ฐฉ๊ฐ) 1POST /product/stock HTTP/1.0 2Content-Type: application/www-form-urlencoded 3Content-Length: 30 4 5stockApi=http://localhost/admin ๋ฐฉ์–ด ์ฐจ๋‹จ๋œ ๋ฌธ์ž์—ด์„ URL ์ธ์ฝ”๋”ฉ ๋˜๋Š” ๋Œ€์†Œ๋ฌธ์ž ๋ณ€ํ˜•์„ ํ†ตํ•ด ์ˆจ๊น€ ์„œ๋กœ ๋‹ค๋ฅธ ํ”„๋กœํ† ์ฝœ์„ ์‚ฌ์šฉํ•˜์—ฌ, ์š”์ฒญ์„ ๋ณด๋ƒ„ using @ 1https://expected-host:fakepassword@evil-host using # 1https://evil-host#expected-host Rogue DNS 1https://expected-host.evil-host Double encoding : # -> %23 -> %2523 XXE (XML eXternal Entity) Injection XML ํŒŒ์‹ฑ ๊ณผ์ •์—์„œ ๋ฐœ์ƒํ•˜๋Š” ์ทจ์•ฝ์ ์„ ์ด์šฉํ•˜์—ฌ, ๊ณต๊ฒฉํ•˜๋Š” ๊ธฐ๋ฒ• XML custom entity XML์—์„œ ์‚ฌ์šฉ์ž๊ฐ€ ์ •์˜ํ•œ ์—”ํ‹ฐํ‹ฐ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ, ์žฌ์‚ฌ์šฉ ๊ฐ€๋Šฅํ•œ ๋ฌธ์ž์—ด์„ ์ •์˜ 1<?xml version="1.0" encoding="UTF-8"?> 2<!DOCTYPE message [<!ENTITY greeting "Hello, ">]> 3<message> 4 <text>&greeting;world!</text> 5</message> Access internal file XML ์—”ํ‹ฐํ‹ฐ๋ฅผ ์ด์šฉํ•˜์—ฌ, ์„œ๋ฒ„์˜ ํŒŒ์ผ์„ ์ฝ์–ด์˜ค๋Š” ๊ณต๊ฒฉ 1<?xml version="1.0" encoding="UTF-8"?> 2<!DOCTYPE foo[<!ENTITY xxe SYSTEM "file:///etc/passwd">]> 3<stockCheck><productId>&xxe;</productId></stockCheck> With SSRF SSRF์™€ ๊ฒฐํ•ฉํ•˜์—ฌ, ์™ธ๋ถ€ ์„œ๋ฒ„๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด๋Š” ๊ณต๊ฒฉ 1<!DOCTYPE foo[<!ENTITY xxe SYSTEM "http://localhost/admin">]> ์•”ํ˜ธ๊ธฐ์ˆ  ์ „ํ†ต์ ์ธ ์•”ํ˜ธ๊ธฐ์ˆ  ์•”ํ˜ธ์˜ ์ •์˜ ์•”ํ˜ธ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๋ชฉ์  ๊ธฐ๋ฐ€์„ฑ (Confidentiality) : ์ •๋ณด๊ฐ€ ๋…ธ์ถœ๋˜์ง€ ์•Š์•„์•ผํ•จ ์ž๋ฃŒ์˜ ๋ฌด๊ฒฐ์„ฑ (Data Integrity) : ๋ฐ์ดํ„ฐ๊ฐ€ ์œ„๋ณ€์กฐ๋˜๋ฉด ์•ˆ๋จ ์ธ์ฆ (Authentication) : ์ •๋ณด์˜ ์ถœ์ฒ˜๊ฐ€ ์ •๋‹นํ•ด์•ผํ•จ ๋ถ€์ธ๋ฐฉ์ง€ (Non-repudiation) : ์‚ฌ์šฉ์ž๊ฐ€ ์ด๋ฅผ ๊ฑฐ๋ถ€ํ•˜์ง€ ์•Š์•„์•ผํ•จ ์•”ํ˜ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ๊ธฐ๋ณธ ์กฐ๊ฑด (K : Key, M : Message, C : Cipher Text) ์•”ํ˜ธํ™” : E(K, M) = C ๋ณตํ˜ธํ™” : D(K, C) = C E(K, M)๊ณผ D(K, C)์˜ ๊ณ„์‚ฐ์€ ์‰ฌ์›Œ์•ผ ํ•จ K๋ฅผ ๋ชจ๋ฅผ๋•Œ C์—์„œ M์„ ๊ณ„์‚ฐํ•˜๋Š” ๊ฒƒ์€ ์–ด๋ ค์›Œ์•ผ ํ•จ ์•”ํ˜ธ ํ•ด๋… ๋ฐฉ๋ฒ• Cipher Text Only Attack : ์•”ํ˜ธ๋ฌธ๋งŒ์„ ์ด์šฉํ•˜์—ฌ ํ‰๋ฌธ์„ ์ฐพ๋Š” ๊ณต๊ฒฉ Known Plain Text Attack : ์•”ํ˜ธ๋ฌธ๊ณผ ํ‰๋ฌธ์„ ์ด์šฉํ•˜์—ฌ ํ‚ค๋ฅผ ์ฐพ๋Š” ๊ณต๊ฒฉ Chosen Plain Text Attack : ํ‰๋ฌธ์„ ์„ ํƒํ•˜์—ฌ ์•”ํ˜ธ๋ฌธ์„ ์ฐพ๋Š” ๊ณต๊ฒฉ ์•”ํ˜ธ์˜ ์ข…๋ฅ˜ ๋Œ€์นญํ‚ค(๋น„๋ฐ€ํ‚ค)(๊ด€์šฉํ‚ค) ์•”ํ˜ธ ์•”ํ˜ธํ™”์™€ ๋ณตํ˜ธํ™”์— ๊ฐ™์€ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์•”ํ˜ธ ์‚ฌ์šฉ์ž n๋ช…์— ๋”ฐ๋ผ ํ•„์š”ํ•œ ํ‚ค์˜ ๊ฐœ์ˆ˜ : n(n-1)/2 ์•”ํ˜ธ ์•Œ๊ณ ๋ฆฌ์ฆ˜์˜ ์ข…๋ฅ˜ ๋ธ”๋ก ์•”ํ˜ธ (DES, IDEA, AES) ํ‰๋ฌธ์„ ๋ธ”๋ก์œผ๋กœ ๋‚˜๋ˆ„์–ด ์•”ํ˜ธํ™”ํ•˜๋Š” ๋ฐฉ์‹ ์ŠคํŠธ๋ฆผ ์•”ํ˜ธ (RC4) ํ‰๋ฌธ๊ณผ ํ‚ค๋ฅผ ๋น„ํŠธ ๋‹จ์œ„๋กœ XORํ•˜์—ฌ ์•”ํ˜ธํ™”ํ•˜๋Š” ๋ฐฉ์‹ ํ•œ๊ตญ์—์„œ ์“ฐ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์ข…๋ฅ˜ : NEAT, SEED, NES, ARIA ๊ณต๊ฐœํ‚ค(๋น„๋Œ€์นญํ‚ค) ์•”ํ˜ธ ์•”ํ˜ธํ™”์™€ ๋ณตํ˜ธํ™”์— ๋‹ค๋ฅธ ํ‚ค๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์•”ํ˜ธ ์‚ฌ์šฉ์ž n๋ช…์— ๋”ฐ๋ผ ํ•„์š”ํ•œ ํ‚ค์˜ ๊ฐœ์ˆ˜ : 2n ๊ธฐ๋ฐ€์„ฑ (Confidentiality) : ๊ณต๊ฐœํ‚ค๋กœ ์•”ํ˜ธํ™”, ๊ฐœ์ธํ‚ค๋กœ ๋ณตํ˜ธํ™” ์ธ์ฆ (Authentication) : ๊ฐœ์ธํ‚ค๋กœ ์•”ํ˜ธํ™”, ๊ณต๊ฐœํ‚ค๋กœ ๋ณตํ˜ธํ™” ํ‚ค ์ƒ์„ฑ DH ํ‚ค ๊ตํ™˜ ์•”ํ˜ธ๊ธฐ์ˆ ์˜ ํ™œ์šฉ ๋””์ง€ํ„ธ ์„œ๋ช… ํŠน์„ฑ : ์œ„์กฐ๋ถˆ๊ฐ€, ๋ณ€๊ฒฝ ๋ถˆ๊ฐ€, ์„œ๋ช…์ž ์ธ์ฆ, ์žฌ์‚ฌ์šฉ ๋ถˆ๊ฐ€, ๋ถ€์ธ ๋ฐฉ์ง€ ๋™ํ˜•์•”ํ˜ธ์™€ ์–‘์ž์•”ํ˜ธ ๊ธฐ์ˆ 
new Spring - JPA : getReferenceById vs findById
๐Ÿƒ Spring
๋ฐฐ๊ฒฝ Service layer์—์„œ createPost ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•˜๋Š” ์ค‘ ์ด์—ˆ๋‹ค Post entity๋Š” User entity์™€ ManyToOne ๊ด€๊ณ„์ด๋‹ค User entity๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐฉ์‹์— ๋”ฐ๋ผ ๋‘๊ฐ€์ง€ ๋ฐฉ์‹์˜ ๊ตฌํ˜„์ด ๊ฐ€๋Šฅํ–ˆ๋‹ค ๋‘ ๋ฐฉ์‹์˜ ์žฅ๋‹จ์ ์„ ํŒŒ์•…ํ•ด๋ณด์•˜๋‹ค getReferenceById ์‚ฌ์šฉ 1public Post createPost(PostDTO.Request postDTO, int userId) { 2 // ํ”„๋ก์‹œ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค 3 User user = userRepository.getReferenceById(userId); 4 5 Post post = Post.builder() 6 .title(postDTO.getTitle()) 7 .content(postDTO.getContent()) 8 .created_at(LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS)) 9 .author(user) 10 .build(); 11 12 try { 13 return postRepository.save(post); 14 } catch (DataIntegrityViolationException e) { 15 throw new EntityNotFoundException("ํ•ด๋‹น ์œ ์ €๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค."); 16 } 17} ์žฅ์  : ์ฟผ๋ฆฌ ํ•œ๋ฒˆ์œผ๋กœ Post entity๋ฅผ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ๋‹ค ๋‹จ์  : insert ์ฟผ๋ฆฌ ์‹คํ–‰ ์ค‘ ๋ฐœ์ƒํ•œ ์˜ˆ์™ธ๋ฅผ ์žก๊ธฐ ๋•Œ๋ฌธ์— ์•ˆ์ •์ ์ด์ง€ ์•Š๋‹ค findById ์‚ฌ์šฉ 1public Post createPost(PostDTO.Request postDTO, int userId) { 2 // ์‹ค์ œ ๊ฐ์ฒด๋ฅผ ๊ฐ€์ ธ์˜จ๋‹ค 3 Optional<User> user = userRepository.findById(userId); 4 5 if (user.isEmpty()) 6 throw new EntityNotFoundException("ํ•ด๋‹น ์œ ์ €๊ฐ€ ์—†์Šต๋‹ˆ๋‹ค."); 7 8 Post post = Post.builder() 9 .title(postDTO.getTitle()) 10 .content(postDTO.getContent()) 11 .created_at(LocalDateTime.now().truncatedTo(ChronoUnit.MILLIS)) 12 .author(user.get()) 13 .build(); 14 15 return postRepository.save(post); 16} ์žฅ์ : insert ์ฟผ๋ฆฌ ์‹คํ–‰ ์ „์— ๋ฏธ๋ฆฌ ์˜ˆ์™ธ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ธฐ ๋•Œ๋ฌธ์— ์•ˆ์ •์ ์ด๋‹ค ๋‹จ์ : ์ฟผ๋ฆฌ ๋‘๋ฒˆ์œผ๋กœ ์ธํ•œ ์„ฑ๋Šฅ ์ €ํ•˜๊ฐ€ ๋ฐœ์ƒํ•œ๋‹ค ๊ฒฐ๋ก  ์ฟผ๋ฆฌ๋ฅผ ๋‘ ๋ฒˆ ๋‚ ๋ฆฌ๋”๋ผ๋„ findById ๋ฉ”์†Œ๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ •์ ์ด๋ผ์„œ ์œ ์ง€๋ณด์ˆ˜ํ•˜๊ธฐ ์ข‹์„ ๊ฒƒ ๊ฐ™๋‹ค
new Spring ๊ฐœ๋… - MVC ํŒจํ„ด, Servlet (์„œ๋ธ”๋ฆฟ)
๐Ÿƒ Spring
Servlet ๊ฐœ๋… ํด๋ผ์ด์–ธํŠธ์˜ ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•˜๊ณ , ๊ทธ ๊ฒฐ๊ณผ๋ฅผ ๋ฐ˜ํ™˜ํ•˜๋Š” ์ž๋ฐ” ์›น ํ”„๋กœ๊ทธ๋ž˜๋ฐ ๊ธฐ์ˆ  ์›นํŽ˜์ด์ง€๋ฅผ ๋™์ ์œผ๋กœ ์ƒ์„ฑํ•˜๋Š” ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค Servlet Conainer์˜ ์—ญํ•  Servlet์˜ ์ƒ๋ช…์ฃผ๊ธฐ๋ฅผ ๊ด€๋ฆฌํ•œ๋‹ค ์›น์„œ๋ฒ„์™€์˜ ํ†ต์‹ ์ง€์› ๋ฉ€ํ‹ฐ์“ฐ๋ ˆ๋“œ ์ง€์›, ๊ด€๋ฆฌ ์„ ์–ธ์ ์ธ ๋ณด์•ˆ ๊ด€๋ฆฌ ์˜ˆ์ œ - Servlet ๊ตฌํ˜„ 1public class TestServlet extends HttpServlet { 2 private static final Logger logger = LoggerFactory.getLogger(TestServlet.class); 3 4 @Override 5 public void init() throws ServletException {} 6} doGet, doPost ๋“ฑ์˜ ๋ฉ”์†Œ๋“œ๋ฅผ ๊ตฌํ˜„ํ•ด์„œ http ์š”์ฒญ์„ ์ฒ˜๋ฆฌํ•  ์ˆ˜ ์žˆ๋‹ค Servlet Context๋ฅผ ๋“ฑ๋กํ•˜๋Š” ๋ฐฉ๋ฒ• web.xml ์ž‘์„ฑ web.xml web application์˜ ์„ค์ •์„ ์œ„ํ•œ deployment descriptor (๋ฐฐํฌ ์ง€์ •์ž) ๊ฐ€์žฅ ๊ธฐ๋ณธ์ ์ธ ๋ฐฉ๋ฒ•์ด๋‹ค src/webapp/WEB-INF/web.xml์— ์œ„์น˜ํ•œ๋‹ค 1<?xml version="1.0" encoding="UTF-8"?> 2<web-app version="2.5" xmlns="http://java.sun.com/xml/ns/javaee" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://java.sun.com/xml/ns/javaee 5 http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"> 6 <servlet> 7 <servlet-name>myServlet</servlet-name> 8 <servlet-class>org.academy.abc.servlet.MyServlet</servlet-class> 9 </servlet> 10 <servlet-mapping> 11 <servlet-name>myServlet</servlet-name> 12 <url-pattern>/*</url-pattern> 13 </servlet-mapping> 14</web-app> @WebServet ์‚ฌ์šฉ Servlet์„ ์„ ์–ธํ•˜๋ฉด์„œ ์‚ฌ์šฉํ•œ๋‹ค 1@WebServlet(value="/*", loadOnStartup = 1) 2public class TestServlet extends HttpServlet {...} WebApplicationInitializer ๊ตฌํ˜„ 1public class OrderWebApplicationInitializer implements WebApplicationInitializer { 2 @Override 3 public void onStartup(ServletContext servletContext) throws ServletException { 4 var servletRegistration = servletContext.addServlet("test", new TestServlet()); 5 servletRegistration.addMapping("/*"); 6 servletRegistration.setLoadOnStartup(1); 7 } 8} DispatcherServlet HTTP์š”์ฒญ์„ ์ค‘์•™์ง‘์ค‘์‹์œผ๋กœ ์ฒ˜๋ฆฌํ•˜๋Š” ํ”„๋ก ํŠธ ์ปจํŠธ๋กค๋Ÿฌ์ด๋‹ค MVC ํŒจํ„ด DispatcherServlet์ด Handler mapping์„ ํ†ตํ•ด Handler๋ฅผ ์ฐพ๋Š”๋‹ค Handler adapter๊ฐ€ DispatcherServlet๊ณผ handler ์‚ฌ์ด์˜ ์ค‘๊ฐ„๋‹ค๋ฆฌ ์—ญํ• ์„ ์ˆ˜ํ–‰ํ•œ๋‹ค Controller๋Š” business logic์„ ์ฒ˜๋ฆฌํ•˜๊ณ  model๊ณผ view name์„ ๋ฐ˜ํ™˜ํ•œ๋‹ค Dispatcher servlet์€ model์„ view๋กœ ๋„˜๊ฒจ์„œ view ๊ฒฐ๊ณผ๋ฅผ ํด๋ผ์ด์–ธํŠธ์—๊ฒŒ ๋ฐ˜ํ™˜ํ•œ๋‹ค
new ๋ฐฑ์ค€ - 15486 : ํ‡ด์‚ฌ 2 (G5)
๐Ÿง  Algorithm
1import sys 2input = sys.stdin.readline 3N = int(input()) 4T = [] 5P = [] 6dp = [0]*(N+1) 7 8for _ in range(N): 9 a, b = map(int, input().split()) 10 T.append(a) 11 P.append(b) 12 13for i in range(N-1, -1, -1): 14 if i+T[i] > N: 15 dp[i] = dp[i+1] 16 else: 17 dp[i] = max(P[i]+dp[i+T[i]], dp[i+1]) 18 19print (dp[0]) dp๋ผ๋Š” ๋ณ€์ˆ˜๋ฅผ ๋งŒ๋“ค์–ด์•ผํ•˜๋Š”๋ฐ ์•ˆ ๋งŒ๋“ค๊ณ  ๋ฆฌ์ŠคํŠธ P๋งŒ ๊ฐ€์ง€๊ณ  memoization ํ•˜๋ ค๋‹ค ์‹คํŒจํ–ˆ๋‹ค ์ ํ™”์‹์€ ์ž˜ ์ ์—ˆ์œผ๋‚˜ ์กฐ๊ฑด๋ฌธ์ด ์ž˜ ๋ชป๋˜์–ด์„œ ๋‹ค๋ฅธ ํ’€์ด๋ฅผ ์ฐธ๊ณ ํ–ˆ๋‹ค
new ๋ฐฑ์ค€ - 13398 : ์—ฐ์†ํ•ฉ 2 (G5)
๐Ÿง  Algorithm
1N = int(input()) 2L = list(map(int, input().split())) 3res = 0 4dp = [[-1000]*N for _ in range(2)] 5dp[0][0] = L[0] 6for i in range(1, N): 7 dp[0][i] = max(dp[0][i-1]+L[i], L[i]) 8 dp[1][i] = max(dp[1][i-1]+L[i], dp[0][i-1]) 9 10print (max(max(dp[0]), max(dp[1]))) ์ด๋ฒˆ ๋ฌธ์ œ์—์„œ ์‚ฌ์šฉํ•  dp ๋ฐฐ์—ด์˜ ํฌ๊ธฐ๋Š” N X 2 ์ด๋‹ค. ๋ฐฐ์—ด์€ ์ตœ์†Ÿ๊ฐ’์ธ -1000์œผ๋กœ ์ดˆ๊ธฐํ™”ํ•˜์—ฌ์•ผ ํ•œ๋‹ค
new ๋ฐฑ์ค€ - 2502 : ๋–ก ๋จน๋Š” ํ˜ธ๋ž‘์ด (S1)
๐Ÿง  Algorithm
1D, K = map(int, input().split()) 2L = [(1, 0), (0, 1)] 3 4for i in range(2, D): 5 L.append((L[i-2][0]+L[i-1][0], L[i-2][1]+L[i-1][1])) 6 7A = 1 8B = 2 9 10while True: 11 if A*L[D-1][0] + B*L[D-1][1] == K: 12 break 13 14 if A+1 == B: 15 B += 1 16 A = 1 17 else: 18 A += 1 19 20print (A,'\n',B, sep='') ํ•ด๊ฒฐ๋ฐฉ๋ฒ• N๋ฒˆ์งธ๋‚  ๋–ก ๊ฐœ์ˆ˜๋ฅผ ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด ์ฒซ์งธ๋‚  ๋–ก, ๋‘˜์งธ๋‚  ๋–ก์„ ๊ฐ๊ฐ ๋ช‡๋ฒˆ ๋”ํ•ด์•ผํ•˜๋Š”์ง€ ๋ฆฌ์ŠคํŠธ์— ๊ตฌํ•œ๋‹ค ์ฒซ์งธ, ๋‘˜์งธ ๋‚  ๋–ก์„ ํ•˜๋‚˜ํ•˜๋‚˜ ๋„ฃ์–ด๋ณด๋ฉด์„œ ๋ธŒ๋ฃจํŠธ ํฌ์Šค๋ฅผ ์ˆ˜ํ–‰ํ•œ๋‹ค
new ๋ฐฑ์ค€ - 15681 : ํŠธ๋ฆฌ์™€ ์ฟผ๋ฆฌ (G5)
๐Ÿง  Algorithm
1import sys 2sys.setrecursionlimit(10**6) 3input = sys.stdin.readline 4N, R, Q = map(int, input().split()) 5G = [[] for _ in range(N)] 6cnt = [1]*N 7visited = [False]*N 8 9for _ in range(N-1): 10 a, b = map(int, input().split()) 11 G[a-1].append(b-1) 12 G[b-1].append(a-1) 13 14def dfs(node): 15 visited[node] = True 16 17 for i in G[node]: 18 if not visited[i]: 19 cnt[node] += dfs(i) 20 return cnt[node] 21 22dfs(R-1) 23 24for _ in range(Q): 25 print (cnt[int(input())-1]) ํ˜ผ์ž ํ’€์—ˆ๋‹ค! ์„œ๋ธŒํŠธ๋ฆฌ์— ์†ํ•œ ์ •์ ์˜ ์ˆ˜๋ฅผ memoizationํ•ด๋†“๊ณ  ์ฟผ๋ฆฌ๋งˆ๋‹ค index์˜ ๊ฐ’์„ ์ถœ๋ ฅํ•˜๋ฉด ๋œ๋‹ค sys.stdin.readline ์•ˆ์จ์„œ ์‹œ๊ฐ„ ์ดˆ๊ณผ ํ•œ ๋ฒˆ recursionlimit ์•ˆ ๋Š˜๋ ค์„œ ๋Ÿฐํƒ€์ž„ ์—๋Ÿฌ ํ•œ ๋ฒˆ python3 ์•ˆ ์“ฐ๊ณ  pypy3 ์จ์„œ ๋ฉ”๋ชจ๋ฆฌ ์ดˆ๊ณผ ํ•œ ๋ฒˆ ์ด 3๋ฒˆ ํ‹€๋ ธ๋‹ค
new ๋ฐฑ์ค€ - 1967 : ํŠธ๋ฆฌ์˜ ์ง€๋ฆ„(G4)
๐Ÿง  Algorithm
1import sys 2sys.setrecursionlimit(10**6) 3M = int(input()) 4G = [[] for _ in range(M)] 5 6for _ in range(M-1): 7 a, b, c = map(int, input().split()) 8 G[a-1].append((b-1, c)) 9 G[b-1].append((a-1, c)) 10 11n1 = 0 12tmp = 0 13 14def dfs(node, length): 15 global n1, tmp 16 visit[node] = True 17 if length > tmp: 18 tmp = length 19 n1 = node 20 for child, v in G[node]: 21 if not visit[child]: 22 dfs(child, length+v) 23 24visit = [False]*M 25dfs(0, 0) 26tmp = 0 27visit = [False]*M 28dfs(n1, 0) 29print (tmp) ์ธํ„ฐ๋„ท์—์„œ ์ ‘๊ทผ ๋ฐฉ๋ฒ•์„ ์ฐธ๊ณ ํ–ˆ๋‹ค ํ•ด๊ฒฐ ๋ฐฉ๋ฒ• ์•„๋ฌด ์ •์ ์—์„œ ๊ฐ€์žฅ ๋จผ ์–ด๋–ค ์ •์ ์„ N์ด๋ผ๊ณ  ํ•˜์ž ์ •์  N์—์„œ ๊ฐ€์žฅ ๋จผ ์ •์  ์‚ฌ์ด์˜ ๊ฑฐ๋ฆฌ๊ฐ€ ํŠธ๋ฆฌ์˜ ์ง€๋ฆ„๊ณผ ๊ฐ™๋‹ค ๋А๋‚€ ์  ๋ฃจํŠธ๋ฅผ ๊ตฌํ•  ํ•„์š”๊ฐ€ ์—†๋‹ค๋Š” ๊ฒƒ์„ ๊นจ๋‹ฌ์•˜๋‹ค
new ๋ฐฑ์ค€ - 1167 : ํŠธ๋ฆฌ์˜ ์ง€๋ฆ„ (G2)
๐Ÿง  Algorithm
1import sys 2sys.setrecursionlimit(10**6) 3input = sys.stdin.readline 4 5V = int(input()) 6G = [[] for _ in range(V)] 7for _ in range(V): 8 token = list(map(int, input().split()))[:-1] 9 for i in range(1, len(token), 2): 10 G[token[0]-1].append((token[i]-1, token[i+1])) 11 12def dfs(node, dist): 13 global max_node, max_dist 14 visited[node] = True 15 if dist > max_dist: 16 max_node = node 17 max_dist = dist 18 for n_node, n_dist in G[node]: 19 if not visited[n_node]: 20 dfs(n_node, dist+n_dist) 21 22max_node = 0 23 24max_dist = 0 25visited = [False]*V 26dfs(0, 0) 27max_dist = 0 28visited = [False]*V 29dfs(max_node, 0) 30 31print (max_dist) ์ตœ๊ทผ์— ํ‘ผ “1967: ํŠธ๋ฆฌ์˜ ์ง€๋ฆ„” ๋•๋ถ„์— ์‰ฝ๊ฒŒ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์—ˆ๋‹ค ๊ธฐ์–ตํ•˜์ž ํŠธ๋ฆฌ์˜ ์ง€๋ฆ„ = (์–ด๋–ค ํ•œ ์ •์ ์—์„œ ๊ฐ€์žฅ ๋จผ ์  P)์—์„œ ๊ฐ€์žฅ ๋จผ ์  ์‚ฌ์ด์˜ ๊ฑฐ๋ฆฌ
new ๋ฐฑ์ค€ - 14938 : ์„œ๊ฐ•๊ทธ๋ผ์šด๋“œ (G4)
๐Ÿง  Algorithm
1N, M, R = map(int, input().split()) 2 3item = list(map(int, input().split())) 4G = [[] for _ in range(N)] 5for _ in range(R): 6 a, b, c = map(int, input().split()) 7 G[a-1].append((b-1, c)) 8 G[b-1].append((a-1, c)) 9 10def dfs(node, dist): 11 global result 12 if dist > M: 13 return 14 if not visit[node]: 15 result += item[node] 16 visit[node] = True 17 18 for n_node, n_dist in G[node]: 19 dfs(n_node, dist+n_dist) 20 21max_result = 0 22 23for i in range(N): 24 result = 0 25 visit = [False]*N 26 dfs(i, 0) 27 max_result = max(max_result, result) 28 29print (max_result) ๋ถ„๋ฅ˜์— ๋‹ค์ต์ŠคํŠธ๋ผ, ํ”Œ๋กœ์ด๋“œ-์›Œ์…œ๋กœ ๋˜์–ด์žˆ์ง€๋งŒ DFS๋กœ ํ’€์—ˆ๋‹ค ํ’€์ด ๋ฐฉ๋ฒ• ์—ฌ๊ธฐ์„œ๋Š” ์žฌ๋ฐฉ๋ฌธ ํ–ˆ๋‹ค๊ณ  ํ•ด์„œ ํƒ์ƒ‰์„ ํ•˜์ง€ ์•Š์œผ๋ฉด ์•ˆ๋œ๋‹ค ์žฌ๋ฐฉ๋ฌธํ–ˆ์„๋•Œ ์ „์— ๋ฐฉ๋ฌธํ–ˆ์„ ๋•Œ๋ณด๋‹ค ๋” ์งง์€ ํ†ต๋กœ๋กœ ๋“ค์–ด์™”๋‹ค๋ฉด ๋” ๋งŽ์€ ์•„์ดํ…œ์„ ์–ป์„ ์ˆ˜ ์žˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค ๋‹ค๋งŒ, ์•„์ดํ…œ์€ ๋ฐฉ๋ฌธํ•  ๋•Œ๋งˆ๋‹ค ์–ป์„ ์ˆ˜ ์žˆ๋Š” ๊ฒƒ์ด ์•„๋‹ˆ๊ธฐ ๋•Œ๋ฌธ์— ์ฃผ์˜ํ•˜์—ฌ์•ผ ํ•œ๋‹ค ์œ„์˜ ๋‚ด์šฉ์„ ์งˆ๋ฌธ๊ฒŒ์‹œํŒ์„ ๋ณด๋‹ค๊ฐ€ ๊นจ๋‹ซ๊ณ  ํ’€ ์ˆ˜ ์žˆ์—ˆ๋‹ค
new ๋ฐฑ์ค€ - 5639 : ์ด์ง„ ๊ฒ€์ƒ‰ ํŠธ๋ฆฌ (G5)
๐Ÿง  Algorithm
ํ’€์ด๋ฐฉ๋ฒ• 1 : ์ง์ ‘ ๊ตฌํ˜„ 1import sys 2 3sys.setrecursionlimit(10**6) 4class Node: 5 def __init__(self, value): 6 self.value = value 7 self.left = None 8 self.right = None 9 10class BinaryTree: 11 def __init__(self, root): 12 self.root = root 13 14 def insert(self, value): 15 cur_node = self.root 16 while True: 17 if value < cur_node.value: 18 if cur_node.left != None: 19 cur_node = cur_node.left 20 else: 21 cur_node.left = Node(value) 22 break 23 else: 24 if cur_node.right != None: 25 cur_node = cur_node.right 26 else: 27 cur_node.right = Node(value) 28 break 29 30 def traverse(self, node): 31 if node.left != None: 32 self.traverse(node.left) 33 if node.right != None: 34 self.traverse(node.right) 35 print (node.value) 36try: 37 tree = BinaryTree(Node(int(input()))) 38except: 39 exit() 40 41while True: 42 try: 43 tree.insert(int(input())) 44 except: 45 break 46 47tree.traverse(tree.root) ์ง์ ‘ ํŠธ๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ•˜์—ฌ ํ•ด๊ฒฐํ•˜์˜€๋‹ค ํ’€์ด๋ฐฉ๋ฒ• 2 1import sys 2sys.setrecursionlimit(10**6) 3 4L = [] 5while True: 6 try: 7 L.append(int(input())) 8 except: 9 break 10 11def traverse(root, end): 12 if root > end: 13 return 14 mid = end + 1 15 16 for i in range(root+1, end+1): 17 if L[root] < L[i]: 18 mid = i 19 break 20 21 traverse(root+1, mid-1) 22 traverse(mid, end) 23 print (L[root]) 24 25traverse(0, len(L)-1) ํŠธ๋ฆฌ๋ฅผ ๊ตฌํ˜„ํ•˜์ง€ ์•Š๊ณ  ํ‘ธ๋Š” ํ’€์ด๋Š” ์ธํ„ฐ๋„ท์„ ์ฐธ๊ณ ํ•˜์˜€๋‹ค ์ „์œ„ ์ˆœํšŒํ•œ ๊ฒฐ๊ณผ๋ฅผ ๋ฆฌ์ŠคํŠธ์— ์ €์žฅํ•œ ํ›„, root ๊ธฐ์ค€์œผ๋กœ ๋‚˜๋ˆ ์ง€๋Š” mid๋ฅผ ์ฐพ์•„ root๊ธฐ์ค€ ์™ผ์ชฝ, root๊ธฐ์ค€ ์˜ค๋ฅธ์ชฝ์„ ๊ฐ๊ฐ ์žฌ๊ท€์ ์œผ๋กœ ์ˆœํšŒํ•˜๋Š” ๋ฐฉ๋ฒ•์ด๋‹ค.
new ๋ฐฑ์ค€ - 1043 : ๊ฑฐ์ง“๋ง (G4)
๐Ÿง  Algorithm
1N, M = map(int, input().split()) 2T = list(map(int, input().split())) 3T = set(T[1:]) 4 5member = [set() for _ in range(N)] 6party = [] 7visit = [False]*M 8 9def explore(n): 10 for i in member[n]: 11 if not visit[i]: 12 visit[i] = True 13 for j in party[i]: 14 explore(j-1) 15 16for i in range(M): 17 lst = list(map(int, input().split())) 18 lst = lst[1:] 19 for j in lst: 20 member[j-1].add(i) 21 party.append(set(lst)) 22 23for i in T: 24 explore(i-1) 25 26cnt = 0 27for i in visit: 28 if not i: 29 cnt += 1 30 31print (cnt) ๋‚ด๋ฐฉ์‹๋Œ€๋กœ ํ‘ธ๋Š”๋ฐ ์˜ค๋ž˜๊ฑธ๋ ธ๋‹ค ์œ ๋‹ˆ์˜จ ํŒŒ์ธ๋“œ๋กœ ํ‘ธ๋Š” ์‚ฌ๋žŒ๋„ ์žˆ์—ˆ๋‹ค
new ๋ฐฑ์ค€ - 2448 : ๋ณ„ ์ฐ๊ธฐ - 11 (G4)
๐Ÿง  Algorithm
1import math 2 3N = int(input()) 4K = int(math.log2(N//3)) 5arr = [[' '] * (2*N-1) for _ in range(N)] 6 7 8def solve(depth, bx, by): 9 if depth == 0: 10 for i in range(3): 11 for j in range(i*2+1): 12 arr[by+i][bx+(2-i)+j] = '*' 13 arr[by+1][bx+2] = ' ' 14 else: 15 px = 2**(depth)*3 16 py = 2**(depth-1)*3 17 solve(depth-1, bx+px//2, by) 18 solve(depth-1, bx, by+py) 19 solve(depth-1, bx+px, by+py) 20solve(K, 0, 0) 21for i in arr: 22 print (''.join(i)) ํ˜ผ์ž ํ’€์—ˆ๋‹ค ๋ณ„์ด ์ฐํ˜€์ ธ์žˆ๋Š” ๋ชจ์Šต์„ ๋ณด๊ณ  ๊ทœ์น™์„ ์ฐพ์•„๋‚ด์„œ ๊ตฌํ˜„ํ•˜๋Š” ๋ฌธ์ œ์˜€๋‹ค N์ด 3*(2^N)์œผ๋กœ๋งŒ ์ฃผ์–ด์ง„๋‹ค๋Š” ๊ฒƒ์„ ํ† ๋Œ€๋กœ ์žฌ๊ท€๋ฅผ ์ด์šฉํ•˜์—ฌ ํ’€์—ˆ๋‹ค
  • ««
  • «
  • 13
  • 14
  • 15
  • 16
  • 17
  • »
  • »»
๐Ÿง  Algorithm (104) ๐ŸŒŠ C/CPP (2) โ˜• Java (8) ๐ŸŒ Javascript (9) ๐Ÿ Python (9) ๐Ÿƒ Spring (30) ๐Ÿ”จ ๊ฐœ๋ฐœ ๋„๊ตฌ (2) ๐ŸŽธ ๊ธฐํƒ€ (7) ๐Ÿ‘จโ€๐Ÿ’ป ๋ชจ๊ฐ์ฝ” (38) ๐Ÿค– ์ธ๊ณต์ง€๋Šฅ (2) ๐Ÿซ ํ•™๊ณผ ๊ณต๋ถ€ (28)
๐Ÿท๏ธ boj (53) ๐Ÿท๏ธ c (5) ๐Ÿท๏ธ c++ (4) ๐Ÿท๏ธ celery (2) ๐Ÿท๏ธ cs (18) ๐Ÿท๏ธ django (3) ๐Ÿท๏ธ docker (2) ๐Ÿท๏ธ docker compose (1) ๐Ÿท๏ธ elk (1) ๐Ÿท๏ธ fastapi (4) ๐Ÿท๏ธ git (2) ๐Ÿท๏ธ github actions (5) ๐Ÿท๏ธ hackerrank (3) ๐Ÿท๏ธ https (2) ๐Ÿท๏ธ java (37) ๐Ÿท๏ธ javascript (2) ๐Ÿท๏ธ jwt (1) ๐Ÿท๏ธ kubernetes (4) ๐Ÿท๏ธ nginx (2) ๐Ÿท๏ธ ocaml (1) ๐Ÿท๏ธ open source (2) ๐Ÿท๏ธ programmers (48) ๐Ÿท๏ธ pytest (1) ๐Ÿท๏ธ python (111) ๐Ÿท๏ธ rabbitmq (2) ๐Ÿท๏ธ rag (3) ๐Ÿท๏ธ react (6) ๐Ÿท๏ธ security (3) ๐Ÿท๏ธ software-engineering (3) ๐Ÿท๏ธ spring (31) ๐Ÿท๏ธ sql (5) ๐Ÿท๏ธ ssl (1) ๐Ÿท๏ธ testing (4) ๐Ÿท๏ธ typescript (1) ๐Ÿท๏ธ vercel (1) ๐Ÿท๏ธ websocket (1)