회고

20191126 회고 - 프로그래밍 패턴

JeongHyeongKim 2019. 11. 26. 00:52

1. 예외 처리

 

def S3ObjectDownload(bucket, key): 
 
    # S3에 자원에 접근 할 access key와 secret key를 입력합니다. 
    s3 = boto3.resource('s3', aws_access_key_id='<YOUR ACCESS KEY>', aws_secret_access_key='YOUR_SECRET_KEY') 
 
    # 추출 된 key에서 경로 값을 제외한 순수 파일 명을 얻기 위한 작업 
    preOutPutName = key.split('/') 
    outPutName = preOutPutName[-1] 
 
 
    # 파라미터로 받은 값을 이용하여 가장 최근에 올린 파일을 EC2로 다운로드 
    s3.Bucket(bucket).download_file(key, outPutName) 
    print("Download successfully.") 
    ProduceKafkaMsg(outPutName) 

위 코드 중 4번째 줄에서 S3의 object에 접근하는 코드가 있다. 접근하고자 하는 object의 존재 유무에 따른 예외처리를 하고 있지 않기 때문에 개발하는데는 문제가 없지만, production 환경에서 클라이언트가 어떤 오류인지 알 수 없기 때문에 오류에 대해 계속 문의가 들어올 수 밖에 없다.

 

 

 

msgJson = json.loads(request.body.decode('utf-8')) 
    msgType=msgJson["Type"] 
 
    # AWS SNS notification 메시지를 구독 전, 구독 확인 요청 승인 
    if msgType=='SubscriptionConfirmation': 
        subscribeURL=msgJson["SubscribeURL"] 
        requests.get(subscribeURL) 
 
 
    # AWS SNS notification 구독 메시지에 대한 다음 작업의 trigger 
    elif msgType=="Notification": 
 
        msgJson = json.loads(request.body.decode('utf-8')) 
        message_data = json.loads(msgJson["Message"].decode('utf-8')) 
        record_data=message_data["Records"] 
        s3_data=None 
 
        for item in record_data: 
            s3_data=item["s3"] 
 
        # S3 Bucket 이름 추출 
        bucket = s3_data["bucket"] 
        name = bucket["name"] 

다음 코드는 Amazon SNS에서 전송한 message body를 json parsing하는 부분이다. json 중 “Type“ 속성을 기반으로 동작을 구분하는데, SubscriptionConfirm과 notification 이외의 값이 들어왔을 경우의 코드가 없기 때문에 좋지 않은 코드이다.

 

 

1.1. 개선 사항

  • try-catch를 이용한 예외 사항에 대한 분기 처리

  • 분기를 통해 어떤 에러인지 사용자가 알 수 있도록 response의 body에 에러 내용을 포함

  • 가능한 여러가지 상황에 대해서 코드로 표현 할 수 있도록 해야함.

 

 

 

 

 

2. 입력 값에 대한 validation

 

    producer = KafkaProducer(bootstrap_servers='<YOUR_BROKER_SERVER>:<YOUR_BROKER_PORT>', 
                             value_serializer=lambda v: json.dumps(v).encode('utf-8'), 
                             key_serializer=lambda v: json.dumps(v).encode('utf-8'), 
                             acks=1, max_request_size=1999999999, send_buffer_bytes=1999999999, 
                             buffer_memory=1999999999) 

위 코드는 Apache Kafka 라이브러리를 사용하여 broker에게 보낼 때, producer에 대한 설정 값을 명시하는 부분이다. Kafka에서 정해진 규격을 지키지 않으면 Kafka broker측에서 에러를 출력하여 적절하게 동작하지 않기 때문에 이에 대한 validation이 필요하다.

 

 

2.1. 개선 사항

  • 설정 값들의 허용 범위에 대한 validation 설정

 

 

 

 

 

3. Static 변수에 대한 처리

    producer = KafkaProducer(bootstrap_servers='<YOUR_BROKER_SERVER>:<YOUR_BROKER_PORT>', 
                             value_serializer=lambda v: json.dumps(v).encode('utf-8'), 
                             key_serializer=lambda v: json.dumps(v).encode('utf-8'), 
                             acks=1, max_request_size=1999999999, send_buffer_bytes=1999999999, 
                             buffer_memory=1999999999) 
s3 = boto3.resource('s3', aws_access_key_id='<YOUR ACCESS KEY>', aws_secret_access_key='YOUR_SECRET_KEY')

위 코드의 경우는 프로세스에 필요한 설정 값을 명시하는 부분이며, 사용자로부터 값을 입력 받기 때문에 코드 상에서 보기 쉬운 위치에 있어야 하며, 재사용이 쉬워야 한다.

 

 

 

 

3.1. 개선 사항

  • 전역적으로 사용되는 static한 변수에 대해 전역변수화 (잘 보이는 곳에 명시)

  • 또는 함수의 파라미터로 입력 받도록 설계

 

 

 

 

 

4. HttpRequest의 200 OK로 고정된 Response

def index(request): 
    # 1. Amazon SNS 서비스의 메시지 구독 요청과 메시지에 핸들링에 대한 샘플입니다. 
    # 2. SNS 메시지 형식과 사용법에 대해서는 Amazon SNS.md를 참조해주세요. 
    # 3. Kafka 라이브러리에 대한 자세한 설명은 본 KafkaProducer.py를 참조해주세요. 
    # 4. KafkaProducer.py는 python3 환경에서 제작된 샘플입니다. 
 
 
 
    msgJson = json.loads(request.body.decode('utf-8')) 
    msgType=msgJson["Type"] 
 
    # AWS SNS notification 메시지를 구독 전, 구독 확인 요청 승인 
    if msgType=='SubscriptionConfirmation': 
        subscribeURL=msgJson["SubscribeURL"] 
        requests.get(subscribeURL) 
 
 
    # AWS SNS notification 구독 메시지에 대한 다음 작업의 trigger 
    elif msgType=="Notification": 
 
        msgJson = json.loads(request.body.decode('utf-8')) 
        message_data = json.loads(msgJson["Message"].decode('utf-8')) 
        record_data=message_data["Records"] 
        s3_data=None 
 
        for item in record_data: 
            s3_data=item["s3"] 
 
        # S3 Bucket 이름 추출 
        bucket = s3_data["bucket"] 
        name = bucket["name"] 
 
 
        # 다운로드 하고자 하는 S3 Object 파일 이름을 추출 
        # 버킷 안에 존재하는 디렉토리 안에 파일이 존재할 경우, 
        # 추출 되는 파일 이름(key 값)은 <directory>/<file_name>의 형태로 출력됩니다. 
        s3object = s3_data["object"] 
        key = s3object["key"] 
 
 
        S3ObjectDownload(name, key)  
 
 
 
    return HttpResponse(request.body) 

각 상황에 맞게 적절한 응답을 취해주어야 하나, 이에 대한 예외 처리가 안되어 있고, django HttpResponsee의 기본 값인 200 OK만 계속 전달되고 있는 상황이다.

 

 

4.1. 개선 사항

  • 각 예외 상황에 맞는 에러코드와 body, header를 반환한다.

 

 

5. 주석

 

from __future__ import unicode_literals 
from django.views.decorators.csrf import csrf_exempt 
from django.shortcuts import render 
from django.http import HttpResponse 
import logging 
import json 
import requests 
import os 
from kafka import KafkaProducer 
import botocore 
import boto3 
 
 
logger = logging.getLogger(__name__) 
 
@csrf_exempt 
def index(request): 
    # 1. Amazon SNS 서비스의 메시지 구독 요청과 메시지에 핸들링에 대한 샘플입니다. 
    # 2. SNS 메시지 형식과 사용법에 대해서는 Amazon SNS.md를 참조해주세요. 
    # 3. Kafka 라이브러리에 대한 자세한 설명은 본 KafkaProducer.py를 참조해주세요. 
    # 4. KafkaProducer.py는 python3 환경에서 제작된 샘플입니다. 
 
 
 
    msgJson = json.loads(request.body.decode('utf-8')) 
    msgType=msgJson["Type"] 
 
    # AWS SNS notification 메시지를 구독 전, 구독 확인 요청 승인 
    if msgType=='SubscriptionConfirmation': 
        subscribeURL=msgJson["SubscribeURL"] 
        requests.get(subscribeURL) 

처음 보는 사람 입장에서 이 라이브러리가 어떤 라이브러리인지, 어떤 함수인지에 대한 정보가 없다. 읽는 사람으로 하여금 의문만 더 증폭시키는 코드가 된거같다.

 

 

5.1. 개선할 사항

  • 함수의 implement 여부, 파라미터, 웹 어플리케이션의 경우 Context 등에 대해 서술

  • 라이브러리가 어떤 라이브러리인지 설명이 필요

 

 

 

 

 

 

6. 코드의 모듈화(자바의 경우, 패키지화)

view.py에 모든 매서드와 기능들이 존재하기 때문에 어떤 부분에서 어떤 역할을 담당하는지 모호하다.

 

 

6.1. 개선할 사항

  • 워크 플로우 정의대로 비슷한 성격의 동작끼리 모듈화시켜 다른 파일로써 보관한다.

'회고' 카테고리의 다른 글

20200624 회고 - 배치 프로세스 및 데이터베이스  (0) 2020.07.28
2019 회고  (1) 2020.02.01