[오픈소스] 오픈소스 기여하기 & 스프링 프레임워크 기여 경험

오픈소스 기여하기

1.왜 오픈소스 프로젝트에 기여해야 하는가?

1.1. 실력 향상

다양한 사람의 코드를 읽음으로써 코드 작성자의 노하우, 코딩 스타일을 접할 수 있음.
또한, 대형 오픈 소스 프로젝트는 코드 컨벤션코드 작성 스타일에 대한 표준을 적용하기 때문에 클린 코드 관점에서 배울 점이 많음.

1.2. 멘토를 찾고 사람들과 배움을 주고 받을 수 있다

오픈 소스는 PR에 대한 리뷰 과정이 있음. 리뷰어는 PR에 대한 피드백을 제공해줌. 이러한 과정에서 리뷰어는 지식을 공유할 수 있고, 리뷰를 받는 사람은 리뷰어로부터 기술 지식, 커뮤니케이션 스킬을 습득할 수 있음.

1.3. 평판과 경력

라이센스에 따라 차이는 있으나 오픈 소스는 공개되어 있으므로, 오픈 소스에 대한 기여를 통해 다른 사람들에게 자신의 능력을 어필할 수 있는 기회를 제공해줌.

1.4. 커뮤니케이션 능력 향상

오픈 소스에 대해 PR을 요청하면, 해당 이슈에 대한 토론이 시작됩니다. 프로젝트 소유자 및 기여자 등 다양한 사람들과 본인이 제시한 이슈 혹은 PR에 대해 추가 설명을 하기도 하고, 수정 사항에 대한 토론을 주고 받아야 합니다. 이러한 과정은 개발자 간의 커뮤니케이션 능력을 향상시키는 경험을 제공해줍니다.

2. spring-framework 오픈 소스 기여 경험 공유

2.1. Spring?

  • 2002년 로드 존슨의 "J2EE Design and Development" 책으로부터 시작
  • 책 출간 이후 Jurgen Hoeller(유겐 휠러), Yann Caroff(얀 카로프)가 로드 존슨에게 오픈소스 프로젝트 제안
  • 2021년 6월 현재 최신 버전 : 스프링 프레임워크 5.3.8, 스프링 부트 2.5.1
  • Spring 프로젝트 Github URL : https://github.com/spring-projects


2.2. Contribute 과정

실제 Pull Request URL : https://github.com/spring-projects/spring-framework/pull/26855

1) 발견

spring-webmvc의 DispatcherServlet 클래스의 doDispatch 메서드 로직 내 HTTP method에 대한 하드코딩 발견

[SpringBoot]스프링 MVC 패턴 설계
[Spring]Servlet & Spring-webmvc
CGI에서부터 이어지는 Servlet → Spring MVC의 DispatcherServlet에 이르기까지의 발전 과정을 공부하면서 실제 소스를 열어보게 됨.

수정 사항 발견 방법

  1. 직접 사용하면서 불편한 부분 소스 코드 분석
  2. 프로젝트 Issue 확인

AS-IS : Spring 5.3.6 ver

public class DispatcherServlet extends FrameworkServlet {
    // ... 생략
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        /** 로직 생략 **/
        boolean isGet = "GET".equals(method);
        if (isGet || "HEAD".equals(method)) {
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                return;
            }
        }
        /** 로직 생략 **/
    }
    // ... 생략
}


2) 수정

  1. spring-framework 프로젝트 fork
  2. spring-mvc 프로젝트에 HttpMethod enum 존재 확인
  3. spring-webmvc.gradle 확인 : spring-web 프로젝트 의존성 확인
  4. 소스 수정

⭐ 소스 수정 시 프로젝트에서 요구하는 조건을 지킬 것.

public enum HttpMethod {

	GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;

	private static final Map<String, HttpMethod> mappings = new HashMap<>(16);

	static {
		for (HttpMethod httpMethod : values()) {
			mappings.put(httpMethod.name(), httpMethod);
		}
	}

	/**
	 * Resolve the given method value to an {@code HttpMethod}.
	 * @param method the method value as a String
	 * @return the corresponding {@code HttpMethod}, or {@code null} if not found
	 * @since 4.2.4
	 */
	@Nullable
	public static HttpMethod resolve(@Nullable String method) {
		return (method != null ? mappings.get(method) : null);
	}

	/**
	 * Determine whether this {@code HttpMethod} matches the given
	 * method value.
	 * @param method the method value as a String
	 * @return {@code true} if it matches, {@code false} otherwise
	 * @since 4.2.4
	 */
	public boolean matches(String method) {
		return (this == resolve(method));
	}
}


3) Pull Request & 피드백

  1. 본인 수정 commit을 원본 repository에 PR
  2. 피드백
  3. 피드백에 대한 조치


4) 최종 승인 및 Merge

TO-BE : Spring 5.3.7 ver

public class DispatcherServlet extends FrameworkServlet {
    // ... 생략
	protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        /** 로직 생략 **/
        boolean isGet = HttpMethod.GET.matches(method);
        if (isGet || HttpMethod.HEAD.matches(method)) {
            long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
            if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                return;
            }
        }
        /** 로직 생략 **/
    }
    // ... 생략
}


3. 참고할만한 것들

3.1. 기본 개발 원칙

DRY (Don’t Repeat Yourself)

  • 모든 형태의 정보를 중복해서 사용하지 말자.

KISS (Keep It Simple, Stupid)

  • 멍청할 정도로 간단하게 유지하라.

YAGNI (Yout Ain’t Gonna Need It)

  • 실제로 필요할 때 구현하라. 필요할 것이라고 예상할 때에는 절대 구현하지 말라.

3.2. 객체지향 설계 5대 원칙 (SOLID)

1. SRP (Single Responsibility Principle)

  • 모든 클래스, 메서드는 하나의 책임만을 수행해야 한다.

2. OCP (Open-Closed Principle)

  • 확장에는 열려있고, 변경에는 닫혀있는 구조로 만들어야 한다.

3. LSP (Liskov Substitution Principle)

  • 자식 타입은 부모 타입으로 대체할 수 있다.

4. ISP (Interface Segregation Principle)

  • 하나의 범용적이고 일반적인 인터페이스보다 여러 개의 구체적이고 특정되는 인터페이스가 더 낫다.

5. DIP (Dependency Inversion Principle)

  • 구체가 아닌 추상에 의존하라.
  • 즉, 구체적인 구현체, 클래스가 아닌 인터페이스나 추상 클래스에 의존하라.

3.3. 도서

책 이미지제목저자
Effective Java조슈아 블로크
Head First Design Pattern케이시 시에라,버트 베이츠,엘리자베스 프리먼,에릭 프리먼
클린 코드로버트 C. 마틴
리팩토링마틴 파울러

References