[특강] 좋은 코드를 작성하려면?
브라우저 자동화하기, Selenium
Wait and Call
마우스 이벤트 처리하기
키보드 이벤트 처리하기
행동
긍정적인 자세
남과 비교하지 않기
커리어 길게 보기
질문 잘하기
의사소통 잘하기
문제 정의 잘하기
결과 내기
기술
프로그래밍 언어 선택하기
구문 및 데이터 유형 이해하기
기본 문법 이해 -> 고급 문법 이해
상황에 맞는 구문과 데이터 유형 사용
많이 고민하고 많이 코딩하기
남의 코드 보고 배우고 코드리뷰 받기
깔끔하고 읽기 쉬운 코드 작성
생산성 툴 익히기
Git/Github
IDE
- 단축키, 플러그인 많이 사용해보기
좋은 코드를 작성하는 것은 훌륭한 개발자의 필수 요소
읽기 쉽고, 이해하기 쉽고, 수정하기 쉬운 코드
명확한 이름, 일관된 형식, 의미 있는 주석으로 체계적으로 구성된 코드
테스트가 가능한 코드
클래스와 함수가 하나의 일만 하는 코드
모듈화되고, 중복이 적은 코드
오류 처리가 코드베이스 전체에서 철저하고 일관성 있게 이루어지는 코드
작성자가 아닌 사용자를 염두에 두고 작성한 코드
중요한 기능일수록 더 완벽을 기한 코드
코드 작성 원칙
DRY(Don't Repeat Yourself)
작성한 코드를 필요한 곳에 재사용할 수 있는 방법 찾기
반복문, 함수, 클래스 활용
KISS(Keep It Simple, Stupid)
불필요한 복잡성을 피하고 코드를 가능한 한 단순하게 유지
- 코드를 반드시 짧게 작성해야 하는 것은 아님
- 내장함수 활용
너무 많은 기능을 하나의 함수로 구현하지 말 것
한 함수가 너무 길어지면 여러 개로 나눌 것
읽기 쉽고 이해하기 쉬운 코드를 작성하려고 노력할 것
일반적인 원칙
일관된 포맷 및 이름 지정 규칙
의미 있고 설명적인 변수 이름 사용
적절한 주석 및 문서화
제어 구조와 알고리즘의 효율적인 사용
주니어 개발자나 새로 온 개발자들을 트레이닝시키는 최선의 방법
단점은 리뷰를 해야하는 사람들이 이미 바쁜 사람이라는 점
좋은 코드리뷰 방법
코드리뷰 요청자
요청 시 되도록이면 조금씩 자주 요청
Unit Test와 같이 요청하면 가장 좋음
주석을 최대한 추가하고 무슨 이유에서 뭘 하려고 한 것인지를 설명
리뷰에 대한 피드백을 너무 감정적으로 받아들이지 않기
코드리뷰 진행자
코딩 스타일에 대한 것보다는 코드 자체에 대해 이야기
객관적으로 쓰고, 비판하는 어조는 피하기
충분한 시간을 들여 도움이 되는 리뷰 제공
코드 리뷰에 편리한 툴 사용
어떤 테스트들이 존재하는가?
Unit Test: 모듈의 특정 기능(함수) 테스트
Integration Test: 여러 모듈을 통합하여 하는 한 차원 위의 테스트
Acceptance Test: 트래픽 등을 생성하여 시스템이 부하를 견디는지 확인하는 테스트
UI Test: 최근에는 Selenium 등의 툴을 이용해 웹페이지 자체의 기능을 테스트
테스트의 중요성
많은 회사들이 코드 변경의 일부로 Unit Test를 의무적으로 요구
테스트가 많을수록 이점이 존재
시스템의 안정성 증대
나중에 리팩토링할 경우 혹은 신입 엔지니어들이 코드 수정할 때 편리
Unit Test
자신이 만든 소프트웨어의 특정 기능을 테스트하는 것
특정 입력에 대해 예상되는 출력이 나오면 성공, 아니면 실패
와 같은 형식으로 작성다른 테스트에 비해 가장 낮은 레벨의 기본 테스트
python의 unittest 라이브러리 사용
Test Coverage
실행 가능 경로 중 몇 퍼센트나 테스트가 되었는지를 나타내는 비율
높을수록 시스템이 안정되고, 리팩토링, 신입 직원 작업 시 용이
소프트웨어 소스코드의 변경사항을 관리할 수 있도록 도와주는 프로그램
Git/Github으로 대표됨
사용하는 이유
코드 변경사항을 쉽게 추적 가능
여러 명이 개발 시 코드의 공유와 변경 용이
코드리뷰 기능 지원
코드 백업의 역할
소프트웨어의 새로운 기능을 빠르게 출시하기 위해서는 정기적인 배포가 아닌 기능이 구현되는대로 배포
자동화된 프로세스
관련 코드 커밋
테스트 수행
패키지 생성(빌드)
소프트웨어를 최종적으로 배포하기 위한 형태로 만드는 것
이를 위해서는 충분한 테스트가 필요
패키지 배포
모니터링
보통 DevOps 팀이 담당
구현 방법
코드 repository를 하나로 유지
코드 변경사항을 지속적으로 해당 repository에 반영(CI: Continuous Integration)
Unit Test 작성
안정적인 테스트 환경 구축
빌드 생성 자동화(테스트 포함)
빌드 배포 자동화(CD: Continuous Deployment)
Selenium 프레임워크
Python으로 웹 브라우저를 조작할 수 있는 자동화 프레임워크
pip3 install selenium
Web Driver 프레임워크
웹 브라우저를 제어할 수 있는 프레임워크
pip3 install webdriver-manager
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
# 주어진 명령이 끝나면 드라이버를 종료하도록 with-as 구문 사용
# 크롬 드라이버 객체 생성
with webdriver.Chrome(service = Service(ChromeDriverManager().install())) as driver:
# 요청 전송
driver.get("http://example.com")
# <p> 요소 하나 찾기
print(driver.find_element(By.TAG_NAME, "p").text)
# <p> 요소 여러 개 찾기
for element in driver.find_elements(By.TAG_NAME, "p"):
print("Text:", element.text)
# Response의 HTML 문서 확인
print(driver.page_source)
Selenium은 동적 웹사이트에 대한 지원으로 암묵적 기다림(Implicit Wait)과 명시적 기다림(Explicit Wait)을 지원
Implicit Wait: 로딩이 끝날 때까지 지정한 시간 동안 기자림
Explicit Wait: 특정 요소에 대한 제약을 통해 기다림
사용할 사이트: https://indistreet.com/live?sortOption=startDate%3AASC
최근 웹사이트는 스크래핑을 방지하기 위해 랜덤한 class 이름을 사용하는 경우가 많음
-> 여러 가지 해결방안 중 위치를 활용하는 XPath 활용
XPath
XML, HTML 문서 등의 요소의 위치를 경로로 표현하는 것
데스크탑/폴더1/폴더2/...
개발자 도구에서 가져오고 싶은 요소를 클릭해 Copy > Copy XPath
//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]
Implicit Wait
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager
with webdriver.Chrome(service = Service(ChromeDriverManager().install())) as driver:
driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")
# 암묵적 기다림(최대 10초)
driver.implicitly_wait(10)
# 1초 ~ 10초
for i in range(1, 11):
element = driver.find_element(By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[{}]/div/a/div[2]/p[1]'.format(i))
print(element.text)
Explicit Wait
from selenium import webdriver
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.support.ui import WebDriverWait
from webdriver_manager.chrome import ChromeDriverManager
with webdriver.Chrome(service = Service(ChromeDriverManager().install())) as driver:
driver.get("https://indistreet.com/live?sortOption=startDate%3AASC")
# 명시적 기다림
# 타겟으로 명시한 요소를 반환
# Xpath가 다음과 같은 요소가 존재할 때까지 최대 10초 간 기다림
element = WebDriverWait(driver, 10).until(EC.presence_of_element_located((By.XPATH, '//*[@id="__next"]/div/main/div[2]/div/div[4]/div[1]/div[1]/div/a/div[2]/p[1]')))
print(element.text)
from selenium import webdriver
from selenium.webdriver import ActionChains
from selenium.webdriver.chrome.service import Service
from selenium.webdriver.common.by import By
from webdriver_manager.chrome import ChromeDriverManager
driver = webdriver.Chrome(service = Service(ChromeDriverManager().install()))
driver.get("https://hashcode.co.kr/")
driver.implicitly_wait(0.5)
# class가 2개 있는 태그 가져오기
button = driver.find_element(By.CLASS_NAME, "nav-link.nav-signin")
ActionChains(driver).click(button).perform()
from selenium import webdriver
from selenium.webdriver import Keys, ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.common.actions.action_builder import ActionBuilder
from selenium.webdriver.chrome.service import Service
from webdriver_manager.chrome import ChromeDriverManager
import time
driver = webdriver.Chrome(service = Service(ChromeDriverManager.install()))
driver.get("https://hashcode.co.kr/")
time.sleep(1)
# 로그인 버튼 찾아서 클릭
button = driver.find_element(By.CLASS_NAME, "nav-link.nav-signin")
ActionChains(driver).click(button).perform()
time.sleep(1)
# 이메일 입력
id_input = driver.find_element(By.ID, "user_email")
ActionChains(driver).send_keys_to_element(id_input, "입력할 email").perform()
time.sleep(1)
# 비밀번호 입력
pw_input = driver.find_element(By.ID, "user_password")
ActionChains(driver).send_keys_to_element(pw_input, "입력할 비밀번호").perform()
time.sleep(1)
# 로그인 버튼 찾아서 클릭
login_button = driver.find_element(By.ID, "btn-sign-in")
ActionChains(driver).click(login_button).perform()
time.sleep(1)