깃허브에 PR을 잘못했는데 Merge까지 해버린 경우가 있어서 해당 PR을 제거할려고 시도한 경험이 있습니다.

이러한 PR을 완전히 제거하는 방법은 생각보다 간단합니다.

 

https://support.github.com/request

 

해당 링크로 들어가서 다음 과정을 수행하면 됩니당.

 


잘못 올린 PR 완전히 제거하기

 

1. '내가 가지고 있거나 제어하는 리포지토리에서 데이터 제거하기'를 클릭합니다. 

 

 

2. 끌어오기 요청 제거하기를 클릭합니다.

 

3. 여러개의 PR을 제거하고 싶다면 Multiple, 하나의 PR을 제거하고 싶다면 Single을 선택하면 됩니다.

 

4. 이후 해당 질문이 왔을때, PR을 제거할려고 하는 repository의 주소를 입력해줍니다.

 

5. 삭제할려고 하는 PR의 번호를 작성하면 2시간 이내에 삭제가 됩니다.


 

하지만, 저는 위와 같은 메세지를 받았고, PR이 삭제되지 않았습니다.

위의 답변을 보면 알 수 있듯이 삭제할려는 PR과 연관된 브랜치에서 각 PR에 대한 commit을 삭제해줘야 PR을 완전히 삭제할 수 있는데 해당 작업이 시행되어 있지 않았기 때문이었습니다. 이를 위해선 삭제할려는 PR이 있는 repository를 클론하고 git-filter-repo BFG Repo-Cleaner 를 이용하여 PR과 연관된 각 브랜치에서 commit을 삭제해줘야합니다.

 

 

git-filter-repo를 이용해 제거한 과정을 정리해볼려고 합니다.

 


1. repository 클론하기

git clone --mirror https://github.com/your-repository.git
cd your-repository.git

 

--mirror를 사용하는 주요 이유는 다음과 같습니다:

  1. 모든 브랜치와 태그 포함: 전체 저장소의 모든 브랜치와 태그를 포함하여 완전한 복사본을 만듭니다. 이는 특정 커밋을 모든 브랜치와 태그에서 제거하려는 경우 필수적입니다.
  2. 원격 참조 유지: 원격 저장소의 모든 참조를 로컬에 그대로 복사하므로, 원격 저장소의 구조를 로컬에서 정확히 재현할 수 있습니다.
  3. 작업 편의성: git filter-repo와 같은 도구를 사용하여 모든 브랜치와 태그에서 커밋을 제거하는 작업을 한 번에 수행할 수 있습니다

 

2. git-filter-repo 설치

pip install git-filter-repo

 

 

3. 제거할려고 하는 커밋 확인 

git log

 를 이용해 제거할려는 커밋의 해시를 알아냅니다.

 

4. 제거할려는 커밋의 해시를 입력해 해당 커밋 삭제

git filter-repo --commit-callback 'if commit.hash == b"{커밋 해시}": commit.ignore = True'

# 예시
git filter-repo --commit-callback '
def callback(commit, metadata):
    if commit.original_id == b"27d6475280e0d347d8bc88e4edcb149bad3fb248":
        commit.ignore = True
'

 

5. 깃허브 저장소 주소 연결

git remote add https://github.com/your-repository.git

 

6. push

git push --force --all

 


위의 방법으로 삭제할려고 하는 PR과 관련된 커밋을 각 브랜치에서 삭제할 수 있습니다. 이렇게 처리한 뒤에 문의할 때 제공받은 티켓에서 댓글로 삭제했다고 연락하면 담당자가 PR을 완전히 제거해 줍니다. 이상입니다. 글 읽어주셔서 감사합니다.

개발자는 커뮤니케이션 능력이 굉장히 중요하다고 생각합니다. 그렇기에 개발하게될 제품에 대해서 다른 부서에 잘 설명할 수 있어야합니다. 이를 도와주는 PRD에 대해 소개하고 싶습니다.

 

 

PRD란 무엇인가?

PRD(Product Requirements Document)는 제품을 만들거나 업데이트하기 위해 기능을 기획하는 단계에서 요구사항을 개괄적으로 설명하는 문서입니다. 이는 제품을 개발하는 전체 프로세스에서 매우 중요하게 사용됩니다.

 

기획 단계에서는 제품의 비전과 전략을 정의하고,

디자인 단계에서는 제품이 사용자 요구 사항을 충족하고 있는지 확인합니다.

다음으로 개발 단계에서는 기능의 목적과 구현을 확인하고,

테스트 단계에서는 제품이 기술 요구 사항을 충족하는지 확인합니다.

마지막으로 출시 단계에서는 제품이 시장 혹은 사용자의 요구 사항을 충족하는지 확인하는 데 사용합니다.

 

이렇듯 제품을 개발하는 전반적인 과정에서 메뉴얼의 역할을 해주는 중요한 문서입니다.

 

PRD 작성 방법

구글의 프로덕트 매니저인 Omar Eduardo Fernández가 정리한 PRD 작성하는 방법을 작성하겠습니다.

 

1. 사용자 문제 및 비즈니스 우선순위 결정의 근거를 포함해 주세요.

개발할 기능의 우선순위를 명확하게 정해줘야합니다. 이를 통해 해결 방법에 따른 기능과 디자인을 평가하고 복잡성과 사용자 가치의 균형을 맞추는 데 도움이 됩니다.

그리고 이 과정에서 개발 프로세스를 고려하여 사용자 문제와 개발 목표를 검토하고, 해결 방안에 대한 내용을 작성해야 합니다. 해당 내용에는 다음이 포함됩니다. 

  • 사용자 조사 결과
  • 다양한 옵션에 대한 토론과 평가
  • 기술적 한계
  • UX 고려 사항
  • 리소스 및 예산
  • 타임라인 요구 사항

그리고 이 내용들은 이해관계자들과 의사 결정권자와 공유하고 진행이 되어도 괜찮은지 의견을 받아야합니다.

 

2. 해결 방안에 대한 세부 정보를 추가하세요.

PRD에는 개발 및 디자인 프로세스를 고려하여 제안된 해결 방안에 대한 세부 정보가 작성되어 있어야 합니다.

해당 정보에는

  • 사용자 조사 결과를 확인할 수 있는 문서
  • 다양한 옵션이나 아이디어에 관해 토론한 회의 내용
  • 기술적 한계
  • UX 고려 사항
  • 리소스 및 예산 제약
  • 타임라인 요구 사항

등이 포함됩니다. 또한 다른 팀에 대한 종속성 및 관련 링크도 포함되어야 하며, 같이 협업하는 팀원들이 PRD를 이해할 수 있도록 작성되어야 합니다.

 

3. UX 및 개발 설계 문서를 참조하세요.

PRD는 구축해야할 기능과 목적을 명확히 하고 개발, UX 디자인 문서를 포함하여 기능이 구축되는 방식을 문서화합니다.

이 단계에서는 고려된 옵션에 대한 피드백을 제공하고 PRD에 설정된 우선순위를 다시 확인합니다.

설계를 마무리할 때, 제품을 만드는 구성원들과 이야기하여 우선순위를 명확히 하고 사용자 가치와 복잡한 기능의 균형을 맞추는 부분을 설명할 수 있어야 합니다.

 

4. PRD를 업데이트하여 기능 범위를 결정하세요.

PRD를 업데이트하여 기능 범위에 대한 결정을 내리고,

UX 및 개발 설계 문서와 중복되지 않도록 합니다.

  • 중요한 결정과 절충안
  • 기술적 고려 사항
  • 다른 팀에 대한 종속성
  • 사용자 개인정보보호 or 법적 문제 명시

위의 내용을 작성하여 행후 중요한 기능을 활성화하기 위해 특정 버전의 기능을 구축하기로 했다면 이 경우에도 기록합니다.

 

5. 다른 사람들과 공유하여 의견을 구하세요.

PRD 필수 변경 사항을 자주 공유하여 다른 사람들의 의견을 구하는 것이 중요합니다.

PRD에 대한 의견을 구하기 위해 관련 이해관계자와 상호작용하고, 업데이트 사항을 빠르게 공유하여 누락된 사항을 고려할 수 있도록 합니다. 이를 통해 PRD의 결정된 내용과 근거를 빠르게 확인하고, 의견을 나눠 장단점을 고려할 수 있습니다.

 

6. 개발 중에도 PRD를 계속 업데이트 하세요.

개발 중에 기능 범위와 타임라인 사이에서 절충안을 찾아야할 경우가 있기에 PRD를 계속 업데이트하고 타임라인 및 범위에 대한 중요한 업데이트를 다른 팀과 공유해야합니다. 이를 통해 팀은 능동적으로 계획하고 빠르게 문제를 해결할 수 있습니다.

 

 

이렇게 총 6가지의 내용을 정리해 봤습니다. 하지만 위의 내용만 가지고는 어떤 형식으로 PRD를 구현해야 하는지 알기 어렵습니다. 바로 PRD의 구성요소를 알아봅시다.

 

PRD의 구성 요소 7

이는 개발 범위와 회사마다 차이가 있으므로 반드시 모든 요소를 포함해야하는 것은 아닙니다.

1. 제품 개요(요약과 배경)

  • 제품의 목적
  • 해결해야 할 문제에 대한 요약
  • 왜 이 문제를 해결해야 하는지 근거 작성

기획, 개발의 중요성을 강조할 수 있는 근거 데이터(설문조서, 인터뷰, 지표)를 참고하면 좋습니다.

최근 몇 달간 사용성에 대한 이슈가 있거나, VOC(고객의 소리) 내용에 반복적으로 나오는 키워드들을 데어터로 정리할 수도 있습니다. 혹은 신규 개발의 경우 시장의 상황이나 변화, 경쟁사의 제품의 성장 등을 추가할 수 있습니다.

 

2. 비즈니스 목표 혹은 지표

  • 제품을 개발하는 이유
  • 기대되는 비즈니스 성과
  • 제품이 달성해야하는 비즈니스 목표
  • 사용자가 제품을 사용함으로써 달성하고자 하는 비즈니스 결과

를 작성합니다. 현재 시점의 데이터와 예상 가능한 데이터를 비교할 수 있도록 작성하는 것이 좋습니다.

 

1. 비즈니스 목적 분석 : 먼저 비즈니스가 달성하고자 하는 목표를 분석합니다. 예를 들어, 매출 증가, 시장 점유율 확대 등이 될 수 있습니다.

 

2. 키 성과 지표(KPI) : 비즈니스 목표에 따라 측정 가능한 KPI를 식별합니다. 예를 들어, 매출 증가를 목표로 한다면 매출 증가율, 고객 당 평균 거래 금액, 신규 고객 유입 비율 등을 KPI로 사용할 수 있습니다.

 

3. 목표 수치 설정 : 각 KPI에 대해 목표 수치를 설정합니다. 예를 들어, 매출 증가율을 10%로 설정할 수 있습니다.

 

3-1. 핵심 고객/사용자 정의

고객 및 사용자는 제품 기획에서 항상 중심이 됩니다. 만들 제품을 사용할 사용자에 대해 정의해야합니다.

제품에 다양한 기능이 있을수록 사용자는 세분화할 수 있습니다. 신규 개발이 되었을 때 갈증이 해소될 사용자가 어떤 문제와 어려움을 겪고 있는 사용자인지 분명하게 서술해야합니다. 아래와 같은 방법으로 사용자를 정의하는 방법도 있습니다.

 

3-2. 핵심 사용자 여정(CUJ) / 사용자 스토리

CUJ

신규 개발 후 정의한 사용자가 목표한 달성할 수 있는지 작성합니다. CUJ는 사용자의 문제와 필요에 집중하여, 사용자가 제품 또는 서비스를 사용할 때 가장 중요한 요소를 파악하고 해결하는 데 도움이 됩니다.

 

이 떄 중요한 건 사용자 요구에 집중하며, 해결 방안에 집착하지 않는 것입니다. 특정 해결 방안이나 기능에만 집중하게 된다면, 근본적인 문제 해결에서 멀어질 수 있습니다. 이는 문장으로 작성할 수도 있지만, 사용자 여정 지도와 같은 시각화된 자료로 만들기도 합니다.

 

사용자 스토리

사용자 스토리는 사용자가 제품 또는 거비스를 이용할 때 생기는 상황, 목적, 요구사항 등을 간결하고 명확하게 표현한 문장입니다. 다음과 같이 작성할 수 있습니다.

“(고객/사용자 유형)은 (목적/목표)를 위해 (필요/욕구)를 원한다” 
”(고객/사용자 유형)쇼핑을 자주 하는 나는, (목적/목표)결제 정보를 저장하여 
매번 새롭게 정보를 다시 입력할 필요 없이, (필요/욕구)빠르게 결제할 수 있기를 원한다.”

이렇게 작성된 유저 스토리는 제품 또는 서비스를 개발할 때 사용자 중심으로 기능을 설계하고 개발할 수 있도록 도와줍니다.

 

5. 기능적 요구 사항

기능적 요구 사항은 아래 내용과 같이 우선순위를 표시하여 작성합니다. 제품 개발을 하는 팀과 함꼐 상의하며 작성하는 것이 좋습니다.

  1. 먼저 대상 사용자를 정합니다. 예를 들어, 음식 주문 앱의 사용자라면 “음식을 주문하려는 사용자”가 됩니다.
  2. Must Have는 반드시 구현되어야 하는 기능으로, 해당 사용자가 해당 기능 없이는 앱을 사용할 수 없다는 것입니다. 예를 들어, 음식 주문 앱에서는 메뉴를 선택하고 주문을 결제하는 것이 Must Have가 될 수 있습니다.
  3. Should Have는 반드시 필요한 것은 아니지만, 해당 사용자가 매우 필요하다고 생각하는 기능입니다. 예를 들어, 음식 주문 앱에서는 메뉴를 검색할 수 있는 기능이 Should Have가 될 수 있습니다.
  4. Could Have는 선택적인 기능으로, 해당 사용자가 원한다면 사용할 수 있는 기능입니다. 예를 들어, 음식 주문 앱에서는 특정 음식점의 할인 정보를 확인할 수 있는 기능이 Could Have가 될 수 있습니다.

 

 

6. 프로젝트 일정 및 배포 계획

제품 개발 및 출시 일정을 작성합니다.

 

7. 기타 참고 문서

와이어 프레임, 스토리보드, UX 리서치 결과 등등이 첨부되면 좋습니다. 또한 트렌드를 확인할 수 있는 레퍼런스 자료들도 첨부합니다.

 

이상으로 PRD를 작성하는 기본적인 방법을 알아봤습니다. 이를 모두 다 적을 순 없더라도 프로젝트를 시작하기 전에 참고하여 작성하고 개발을 시작한다면 충분히 도움이 될 것이라고 생각합니다. 긴 글 읽어주셔서 감사합니다!

 

 

 

 

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

첫 번째 풀이(오답)

1. 트럭 deque와 0으로 이루어진 다리 deque를 만든다.

2. 트럭 deque가 0일 될때까지 while문을 반복한다. 트럭을 하나 popleft해주고
'다리도 하나 popleft 해준다.'(다리를 이동하는 것을 0 하나를 빼고 트럭을 올리는 거로 표현) 

2-1. 다리 deque의 합과 앞으로 올릴려는 트럭 deque에서 pop한 트럭의 합이 w보다 작거나 같은 경우,

pop한 트럭을 다리에 올려준다.

2-2. 다리 deque의 합과 앞으로 올릴려는 트럭 deque에서 pop한 트럭의 합이 w보다 작거나 같은 경우,

pop한 트럭을 트럭 deque에 appendleft 해주고 '0을 넣어준다.' (다리에 아무것도 올라가지 않았다는 표현)

from collections import deque

def solution(b_l, w, t):
    time = 0
    tque = deque(t)
    bl = deque([0]*b_l)
    
    while tque:
        time += 1
        pop = tque.popleft()
        bl.popleft()
        
        if sum(bl) + pop <= w:
            bl.append(pop)
            continue
        
        if sum(bl) + pop > w:
            bl.append(0)
            tque.appendleft(pop)
            continue

    time += b_l
    return time

로직은 맞았지만 케이스 하나에서 시간 초과가 발생했다. sum을 사용해서 그런 것 같다.

 

두 번째 풀이 (정답)

sum을 어떻게 바꿀지 고민해보자

그리고 무조건 처음에 pop을 하여 트럭을 빼는 방식은 비효율적이다.

다리가 버티는 무게(wei)를 따로 만들어 무게를 더하고 빼주자.

무조건 while 반복문을 시작할때, 다리 deque에서 popleft한 요소를 빼준다.

그리고 트럭 deque도 먼저 빼주지 말고 트럭 deque의 0 인덱스와 wei를 더한 무게를 다리가 버틸 수 있는 하중과 비교해주면 훨씬 간단하게 해결할 수 있다.

 

deque를 사용한 풀이

from collections import deque

def solution(b_l, w, t):
    time = 0
    tque = deque(t)
    bl = deque([0]*b_l)
    wei = 0
    
    while tque:
        time += 1
        wei -= bl.popleft()
        
        if wei + tque[0] <= w:
            wei += tque[0]
            bl.append(tque.popleft())
            continue
        
        if wei + tque[0] > w:
            bl.append(0)
            continue

    time += b_l
    
    return time

 

deque를 사용하지 않는 풀이

def solution(b, w, t):
    time = 0
    bridge = [0]*b
    wei = 0
    
    while len(t) != 0:
        time += 1
        wei -= bridge.pop(0)
        
        if wei + t[0] <= w:
            wei += t[0]
            bridge.append(t.pop(0))
        else:
            bridge.append(0)
        
    time += b
        
    
    return time

 

스택/큐 문제를 풀 때 팁

스택이나 큐에 쌓이는 것을 확인하고 싶을 때 위에서 했던 것처럼 +/-를 이용해 표현할 수 있다.

위에서는 다리에 올라간 트럭의 무게를 빠른 속도로 파악하기 위해 wei를 0으로 초기화하고, 들어오는 트럭과 나가는 트럭의 무게를 뺐는데 이는 스택을 사용하는 것과 같은 효과를 가지고 있다.

 

다리는 지나는 트럭 문제 외에 대표적인 문제로 올바른 괄호 찾기 문제가 있다.

이 문제는 중괄호로 주어진 문자열이 열림과 닫힘의 짝이 맞는 지 확인하는 문제이다.

기본적으로는 무조건 false인 경우를 처리한 후 스택에 문자열 순대로 넣으면서 스택에 들어간 괄호가 (이고 이어서 들어가는 괄호가 ) 라면 없애주고 그렇지 않은 경우는 그냥 계속 넣어준다. 결과적으로 스택에 아무것도 남아있지 않으면 올바른 괄호이고, 스택에 남아있다면 올바른 괄호가 아닌 것이다. 이를 정말 간편하게 변수를 0으로 초기화하고 +와 -로 구현할 수 있다.

def solution(s):
	answer = True
    judge = 0
    
    if s[-1] == '(' or s[0] == ')':
    	return False
    
    while s:
    	pop = s.pop(0)
        
        if pop == '(':
        	judge += 1
        
        if  judge > 0 and pop == ')': 
        # 아무것도 들어오지 않은 상태(0)에서 ')'를 넣으면(-1) 의미가 없기 때문에 아무 조치도 하지 않는다.
        	judge -= 1
        
    if judge != 0:
    	return False
        
    return answer

 

위와 같이 0에 +1 -1을 하는 방식으로 스택을 표현했다. 이를 다른 문제를 풀 때도 고려해보고 적용해보면 좋을 것이라 생각된다.

이전에 키보드 접근성을 고려해 tabIndex를 적용하는 방법에 대해 알아봤습니다.

이를 이용해 제가 진행하고 있는 프로젝트에 적용해보면서 알게된 ARIA 속성에 대해 알려드리고 싶어서 다시 적습니다!

tabIndex로 탭 순서에 포함시켜도 포커싱된 요소가 어떤 요소인지 알 수 없으면 tabIndex를 넣은 의미가 없습니다. 이러한 문제를 해결해 주는 속성이 바로 ARIA 속성입니다.

ARIA 속성

스크린 리더를 사용해 프로젝트를 수정하면서 ARIA 속성에 대해 알게 되었습니다. ARIA  속성을 이용해 스크린 리더 사용자가 포커싱 하고 있는 요소에 대해 자세히 설명할 수 있습니다. 저는 ARIA 속서 중 aria-label로 요소를 설명하며 스크린 리더 사용자들이 앱을 더 자세히 알 수 있도록 조치했습니다.

 

보통은 aria-label은 다른 ARIA 속성과 함께 사용해 스크린 리더 사용자들에게 포커싱 하고 있는 요소에 대해 디테일하게 설명합니다. 

 

이에 대해 조금 더 자세히 설명하겠습니다.
aria-label을 다른 ARIA (Accessible Rich Internet Applications) 속성과 함께 사용하는 것은 웹 페이지의 접근성을 강화하고, 다양한 접근 요구 사항을 충족하기 위함입니다. 각 ARIA 속성은 특정한 접근성 문제를 해결하도록 설계되었으며, 여러 속성을 조합하여 사용하면 보다 풍부하고 명확한 접근성 지원이 가능해집니다.

1. 복합적인 접근성 요구 충족

  • 웹 요소가 단순한 텍스트 레이블 이상의 정보나 상태를 전달해야 하는 경우가 많습니다. 예를 들어, 버튼이 현재 활성화 상태인지, 확장된 상태인지 등의 추가 정보가 필요할 수 있습니다.
  • aria-label은 요소의 기본적인 레이블을 제공하지만, 요소의 상태(aria-expanded, aria-selected 등)나 역할(role 속성) 등을 보다 세밀하게 제공해야 할 때 다른 ARIA 속성과 함께 사용됩니다.

2. 명확한 사용자 인터페이스 제공

  • 사용자 인터페이스 요소가 복잡하거나 다양한 기능을 갖춘 경우, 사용자에게 명확한 안내가 필요합니다. 예를 들어, 탭 인터페이스는 선택된 탭과 선택 가능한 탭을 명확히 구분해야 합니다.
  • aria-label은 각 탭의 기능을 설명하고, aria-controls, aria-selected 등의 속성을 함께 사용하여 탭의 현재 상태와 관리하는 패널을 지정할 수 있습니다.

3. 보다 포괄적인 접근성 지원

  • 일부 사용자는 특정한 보조 기술을 사용하여 웹을 탐색합니다. 이러한 기술은 ARIA 속성을 통해 제공된 정보를 사용하여 콘텐츠를 해석하고 사용자에게 전달합니다.
  • aria-label만으로는 충분한 정보를 제공하지 못하는 경우가 많기 때문에, aria-describedby (요소에 대한 추가 설명 제공), aria-live (동적 콘텐츠 변경 알림) 등과 같은 속성을 함께 사용하여 보다 포괄적인 접근성을 제공할 수 있습니다.

4. 일관된 사용자 경험 유지

  • 웹 접근성은 모든 사용자가 일관되고 동등하게 콘텐츠를 이용할 수 있도록 보장하는 것을 목표로 합니다. 다양한 ARIA 속성을 적절히 조합하여 사용하면, 다양한 요구를 가진 사용자들에게 일관된 경험을 제공할 수 있습니다.

결론

aria-label과 다른 ARIA 속성을 함께 사용하는 것은, 웹 요소의 기능과 상태를 보다 정확하고 효과적으로 전달하기 위해 필요합니다. 이는 웹 접근성을 강화하고, 모든 사용자가 웹 사이트의 기능을 최대한 활용할 수 있도록 지원하는 데 중요한 역할을 합니다.

 

일단 저의 프로젝트에서 대부분의 요소들을 aria-label로 설명이 가능하기 때문에  aria-label만 사용한 경우가 많습니다.

그리고 aria-label을 사용하면 요소 내부의 정보를 스크린 리더가 읽지 못하기 때문에 주의해서 사용해야합니다.

 

(▼ 사용 예시 1)

 

aria-label로 포커싱된 요소에 대해 설명합니다.

 

(▼ 사용 예시 2)

날씨에 맞는 코디를 보여주는 프로젝트이기에 스크린 리더 사용자는 코디의 정보를 알기 어렵습니다. 그렇기에 aria-label을 이용해 어떤 코디를 입었는지 사용자에게 알려줍니다.

+ Recent posts