본문 바로가기

Java

Java로 날씨 알림 서비스를 만들어보자 (OOP, Clean Code)

개발동기

비 오는 날만 알림을 받고 싶다. 세상에 좋은 날씨 애플리케이션은 많다. 그러나 매일 날씨 애플리케이션을 확인하는 것은 번거롭고, 내가 딱 필요한 정보만을 제공해주는 서비스도 (아마) 없다. 그래서 날 위한 서비스를 내가 만들기로 했다. 왜? 난 개발자니깐


작년에 개발실력을 향상하기 위해 온갖 서적과 영상 등을 봤다. 점차 이러한 학습량은 많아졌고, 아는 듯한 느낌은 많이 들었다. 그러나 막상 해보니 겉만 조금 알고 있었고 한계에 직면했다. 다르게 표현하자면 실질적으로 해보지 않고 한 행위들은 마치 연애를 책으로 배운듯한 느낌이 들었다. 그래서 올해부터는 실질적인 코딩에 좀 더 집중하기로 했다. 

신경쓴 것

  • OOP
  • Clean Code 
  • Test Code

스케치

간단하다.

스케줄러를 통해서 7시가 되면

날씨 API에 

HTTP로 요청해서 데이터를 가져온 후

비가 오면 메신저에 알림을 보낸다.


구현체들로 말하자면

ScheduledExecutorService를 통해서 7시가 되면

Weather Planet API에 

OkHttp를 통해 HTTP 요청을 해서 데이터를 가져온 후

비가 오면 Slack 또는 Telegram에 메시지를 보낸다.  

Core

4개의 모듈로 구성되어있다. 코드는 Github에 올라가 있으니 같이 보면 좀 더 좋을 것 같다.



위와 같은 구조를 가지고 있다. (저렇게 봐서는 나도 잘 모르겠다... 참고만 하도록 하자)

1. scheduler

굳이 추상화하지 않았다. (아니 못했다.)

JDK에 내장되어있는 ScheduledExecutorService로 구현을 했다. 외부로 노출되는 메소드는 아래 메소드 하나이며, 몇시 몇분 몇초에 뭔가를 실행을 할 것이라는 것을 알 수 있다. (Java의 ScheduledExecutorService를 이용해서 스케줄러를 만들어보자)

public void execute(int hour, int minute, int second, Runnable command)

2. weather

Rain 클래스는 HTTP 모듈을 가지고 Weather Planet API에 요청을 해서 날씨 정보를 조회한다.

WeatherParams 클래스는 API 요청 시 필요한 파라미터들의 집합이며, seoul()이라는 정적 팩토리 메소드를 통해 간단하게 seoul의 파라미터를 생성할 수 있다.

결과 값은 enum (RainCode)을 사용하였다.

3. http

HttpClient를 인터페이스로 두고 OkHttp를 구현한 OkayHttpClient를 만들었다.

이는 한 라이브러리에만 종속되게 사용하기보다는 상황에 따라 유연하게 다른 라이브러리를 사용할 수 있게 해준다.

예를 들면 OkHttp를 사용하기 싫다면 다른 라이브러리를 사용해서 HttpClient를 구현하면 된다.

그러다 보면 자연스럽게 HttpResponse에 응답 데이터까지 넣게 된다. (누가 Unirest나 HttpURLConnection로 구현 한 후 PR을 날려줬으면...)


그리고 위의 사진에서 m 오른쪽에 자물쇠 표시가 많다. 이는 private 접근자를 의미하며, 주로 public 메소드 내에서 사용하는 의미 있게 나눠진 메소드들이다.

4.  messenger

위와 동일한 패턴이다. Messenger를 인터페이스로 두고 SlackMessenger와 TelegramMessenger를 구현했다.

처음에 Slack을 이용하려고 했는데, Slack UI가 개인적으로 불편해 Telegram으로 바꾸게 되었다. 애초에 인터페이스를 통해 유연하게 설계를 했기 때문에 변경하는 것은 간단했다.

결과

OOP

객체의 역할과 책임에 따른 설계에 대한 고민을 많이 하고 싶었지만, 그 경계가 명확했기 때문에 간단하게 정의할 수 있었다.

그래서 그것보다는 확장 가능하고 유연한 설계에 신경을 썼다.

Clean Code

하나의 메소드는 하나의 일을 하도록 (노력) 했다.

불명확한 숫자들은 상수로 만들어 명확하게 했다.

주석을 쓰기보다는 메소드로 나누거나 메소드명을 명확하게 작성했다.

enum을 통해 if else를 줄였다.

에러가 일어나면 무책임하게 throws로 넘기지 않고, 명시적으로 핸들링을 했다.

Test Code

조금 부족하긴 하지만  80% 근접하게 했다. 외부와의 연결(Http 같은)은 Mock 객체를 통해서 유닛 테스트를 작성하였다. 이는 후에 공격적인 리팩토링이 가능하도록 도왔다.

그리고 http 패키지에서 OkHttp의 Builder 패턴으로 된 기능들이 테스트하기 까다로워서 coverage가 쭉 떨어졌는데, 빨리 방법을 찾아서 고쳐야겠다.

느낀점

사실, 정말 간단한 작업이라고 생각했다. 작업하기도 전에 어떻게 해야 될지 설계까지 머리에 그려질 정도였으니... 그러나 막상 머리에 있는 것을 코드로 써 내려가려고 하니 사소한 부분에서 이런저런 문제가 많았다. 게다가 평소에는 Spring Boot로 작업한 탓에 기본적인 디펜던시를 다 잡아줬는데, 쌩 Java로 하려니 디펜던시에서 고생을 했다. 이는 잘 알지도 못하고 사용하고 있던 나의 모습을 반성시키게 했다.


내게 필요한 서비스를 직접 만든다는 것이 재미있었다. 올해의 첫 토이 프로젝트는 이렇게 잘 마무리가 된 거 같다.(수정해야 될 부분이 있긴 하지만...)

차근차근 필요한 서비스들을 만들다 보면 금방 다방면으로 성장할 수 있을 것 같다.