사이드 프로젝트 주제를 어떤 것으로 정할까 고민하다가 실제로 사용할 수 있는걸 만들어봐야겠다는 생각으로 타바타 타이머를 정했습니다.
저는 크로스핏을 1년째 하고 있는데요.
(살 빼려고 시작했는데 살이 안빠지는 건 의문이긴 합니다.. 체력은 좋아졌습니다!)
끝나고 추가 운동을 하려 타바타 타이머 어플을 받았는데 한번 쓰고 나니 결제를 하라고 하거나 광고가 나오는게 마음에 안들어 직접 만들어보기로 했습니다.
(팀 프로젝트 때문에 타이머 작동이 되게만 개발 후 멈춰있는 중.. ㅠㅠ)
기능을 사용하려면 프로버전으로 업그레이드 하라고 하길래
제 어플은 업그레이드 하지 않아도 프로기능을 제공한다는 의미로 TimerPro 로 정했습니다.
꿈은 크게 꾸라고 여러가지 기능을 만들어 봐야지 하고 피그마로 구상을 하고 제가 제일 필요한 타바타 기능만 먼저 만들어보기로 했습니다.

타바타는 일본의 과학자이자 운동 생리학자인 이즈미 타바타(Izumi Tabata)에 의해 개발된 트레이닝 방식입니다.
운동 방법은 20초 정도 최대한 고강도로 운동 후 10초 휴식을 8번 반복하는 형태로 구성됩니다.
타바타 기능을 만들기 위해서 필요한 것은 다음과 같았습니다.
1. 운동, 휴식, 라운드, 사이클, 사이클 휴식 시간 설정 기능
2. 설정한 시간과 라운드에 맞게 타이머 재생 기능
3. 시작, 중간, 끝날때 소리 알림 기능
먼저 핵심 기능인 timer module을 만들어 보려 합니다.
타이머는 모두 상대시간을 다루는 기능들로 이루어져 있는데요.
타바타 or 라운드 or 스톱워치 어떤 기능을 구현을 하든
T(시간) + Δ(델타)를 다루는 작업이고 진행 시간이 지난 다음에 이벤트를 호출해주는 것의 반복입니다.
그래서 시간이라는 개념을 어떤 인터페이스로 다뤄야 하는가부터 시작했습니다.
일단 시간을 저장할 수 있어야 했습니다.
시간을 어떤 단위로 저장하는 게 좋을까 ?
휴식은 10초 단위로 하니 초단위로 다루는 게 좋을 것 같고 숫자가 너무 커질 가능성도 거의 없을 것 같습니다.
하지만 나중에 ms 단위로 바뀌게 될 수 도 있으니 duration 보다 관심사가 큰 Time으로 지정해 줬습니다.
type Time = { duration: number };
진행하는 시간이 운동인지 휴식인지에 대한 정보는 시간 자체를 의미하는 것은 아니니 조금 더 상위개념이라고 보는게 나을 것 같습니다.
type Schedule = { name: string; time: Time };
그리고 나머지 정보들을 정의해줬습니다.
type Round = {
work: Schedule;
rest: Schedule;
};
type Cycle = {
rounds: Round[];
rest: Schedule;
};
type Template = {
운동: Time;
휴식: Time;
라운드: number;
사이클: number;
사이클휴식: Time;
};
해당 데이터가 저장되는 형식과 타이머에서 사용될 형식은 조금 다른데요
타이머에서 사용할 수 있는 형식으로 변경하는 함수를 만들기로 했습니다.
type ConvertTemplateToSchedule = (t: Template) => Schedule[]
여기서 저장하는 형식과 실제로 사용되는 형식에 차이가 있기 때문에 몇가지 고민이 있었습니다.
- 서버가
Template타입을 주고 타이머에서 그대로 사용하면 매번Template => Schedule[]로 나아가는 함수를 호출해야한다.- 매번 이 연산을 수행하지 않아도 되는 방법이 있을까?
저장 시 Template => T로 변환한다. (T는 그냥 임의의 타입)
저장은 Template으로 하고 불러올 때마다 직접 Schedule[]로 변환한다 (매번 연산해야 함)
나중에 Template을 저장하는 기능이 추가될 것이기 때문에 형식을 저장해두는게 좋을 것 같고 Template 타입이 변경되더라도, Template ⇒ T로 변경해주는 함수의 동작만 변경해주면 되니 타입 변경으로 인한 사이드 이펙트를 최소화할 수 있다는 장점이 있어 저장은 Template으로 하고 불러올 때마다 직접 Schedule[]로 변환하는 방법을 사용했습니다.
type Time = { duration: number };
type Schedule = { name: string; time: Time };
type Round = {
work: Schedule;
rest: Schedule;
};
type Cycle = {
rounds: Round[];
rest: Schedule;
};
type Template = {
운동: Time;
휴식: Time;
라운드: number;
사이클: number;
사이클휴식: Time;
};
type ConvertTemplateToSchedule = (t: Template) => Schedule[]
고민 끝에 정해진 인터페이스 입니다.
항상 느끼는 거지만 합쳐놓은 걸 나중에 뜯는 작업은 너무 어렵습니다.
아 이럴바에 새로 만들지라는 생각을 들게 하구요.
그럼에도 한 프로젝트가 끝날 때 마다 깨달은 것으로
다음에는 더 좋은 설계를 할 수 있고 리팩토링을 하며 코드가 깨끗해지면 그날은 기분이 좋습니다..ㅎ
얼른 팀 프로젝트를 끝내고 다시 돌아와 타이머 완성을 해보도록 하겠습니다 :)