오늘 파이썬 코드 작업 도중 git에 올려야 하는 코드를 제외하고 commit메시지를 작성하였다. 

 

commit을 취소 하기 위해

 

git reset --hard HEAD^

 

를 입력하여 commit을 취소하고 다시 git add 를 실행하는데 Nothing to Commit이라고

 

출력이 되었다. 다시 깃허브 명령어를 보니 --soft 옵션이 아니고 --hard옵션으로 실행되어

 

commit이 취소되는 동시에 해당 파일들은 예전 코드로 변경이 되어 있었다.

 

흘려본적 없는 식은땀이 났고, 고객사에 제출해야하는데 코드가 모두 날아가서 매우 당황스러웠다.

 

git-scm을 찾아서 되돌릴 방법을 찾아 본 결과 획기적인(그 당시의 나에게만) 명령어가 있었다.

 

그 명령어는 다음과 같다.

SYNOPSIS
git reflog <subcommand> <options>




SUBCOMMAND & OPTIONS
git reflog [show] [log-options] [<ref>]
git reflog expire [--expire=<time>] [--expire-unreachable=<time>]
	[--rewrite] [--updateref] [--stale-fix]
	[--dry-run | -n] [--verbose] [--all [--single-worktree] | <refs>…​]
git reflog delete [--rewrite] [--updateref]
	[--dry-run | -n] [--verbose] ref@{specifier}…​
git reflog exists <ref>

 

 

위 documentation을 보고 git reflog을 입력하니 다음과 같이 메시지가 출력이 되었다.

 

다행히 내가 날려먹은 커밋 기록인 "debug on amazon linux_20191126"이 존재하였고,

 

해당 HEAD로 파일들을 reset시켜 기록을 되돌려 놓을 수 있었다. 

 

 

이참에 git reset의 --hard, --soft, --mixed옵션에 대해서 한번 다시 공부하기로 하였다.

 

옵션을 표로 정리해 보았다.

 

  index staged / unstaged 작업 중이던 파일
git reset --hard 해당 index 취소 unstaged로 변경 작업 취소(유실)

git reset --mixed

(Default option)

해당 index 취소 unstaged로 변경 작업 보존
git reset --soft 유지 staged 상태 유지 작업 보존

 

 

이 표로 정리하고 나니, 내가 식은 땀을 흘렸던 상황이었을 때 git reset -mixed를 사용하여 

 

commit을 취소하고, 작업은 살리는 쪽으로 했어야 했었다.

 

다시는 이런 실수 안하겠지...

'IT > Git' 카테고리의 다른 글

[Github] git reset 작업 취소 방법  (0) 2019.11.26

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 회고  (2) 2020.02.01
20191126 회고 - 프로그래밍 패턴  (0) 2019.11.26

어제 학습한 servlet에 대해 의문점이 생겼다.

 

Chrome에서 servlet을 1회 최초 호출하고, Safari에서 servlet을 1회 호출한 결과는 위 사진과 같이 나왔다.

2번 호출 했으니, init 매서드가 2번 호출 될 것이라고 생각했었는데 아니었다.

 

 

 

그 이유는 다음과 같다.

서블릿의 동작과정을 한눈에 보기 쉽게 다이어그램으로 정리해보았다.

 

 

 

 

Servlet는 최초 호출이 되면 해당 selvlet은 메모리에 적재됩니다. 그 이후로 다른곳에서도 중복 호출 하게 되면, 똑같이 Servlet를 불러오는 것이 아니라, 메모리에 적재된 Servlet을 재사용해서 사용자와의 인터페이스를 제공한다고 한다.  Servlet는 메모리에 이미 init()이 실행된 채로 메모리에 적재되어 있기 때문에 또 다시 같은 Servlet을 쓰지 않고도 일반 호출보다 더 빠르게 인터페이스를 제공 할 수 있게 된다.

 

 

다시 한번 정리하면, Servlet는 메모리에 적재된 Servlet을 재사용하기 때문제 일반 웹보다 훨씬 빠르고 효율적으로 인터페이스를 제공 할 수 있도록 도움을 준다.

+ Recent posts