이번주는 이미지 개선작업에 대해서 회고할 내용이 정말 많은 것 같아서 그 부분에 대해서 써야겠다..!
우선 다른 팀 시니어분께서 작성해주신 코드가 너무 깔끔하고 각 함수가 하는 일을 확실히 정의한, 그리고 어느정도 추상화 되어있어 다른 케이스에서도 가져다 쓸 수 있는 구조로 작업을 해주셔서 코드를 보며 너무 감탄했다. 클린 코드 책에서 봤던 내용들이 적용되어있는 Best practice 같은 느낌!
코드를 읽으면서 클린 코드의 내용이 같이 오버랩 되는 정도였다.
나도 언제쯤 저런식으로 스스로 설계를 할 수 있게될까 하는 부러움과 그에 따라 조급한 마음도 들었는데.. 내 것으로 흡수하기 위해 이렇게 복습 겸 회고를 작성해보게 되었다.
누군가가 이 글을 보게 된다면, 주절주절 회고할 겸 적는 내용이라 부족하거나 틀린 부분이 있을 수 있음을 인지해 주시길 바랍니다...🙄
서비스 내에서 이미지가 굉장히 중요한 역할을 하는 컴포넌트들에 대해 에러 핸들링이 되어있지 않았다.
따라서 네트워크 환경이 좋지 않을 경우 유저는 한없이 이미지를 기다리거나, 정상적인 응답을 받지 못한 경우 엑박을 마주하게 되는 상황임을 파악했다.
💡 여기서 중요한 것!
매번 팀 회고에서 나오는 내용이지만, 개발 후 QA를 진행할 때에는 개발자의 관점을 완!벽!히! 내려놓고 해당 서비스를 사용하는 유저에 빙의(?)해야함을 다시 한 번 느꼈다.
해당 서비스의 유저 세그먼트는 일반인보다 파티같은 행사에 참석하는 비율이 높다는 특징이 있고, 그에 따라 사람이 많거나 지하에 위치한 장소, 즉 네트워크 환경이 좋지 않은 상황에서 앱을 실행할 확률이 높다는 점을 간과하고 있었다.
개발 테스트 및 QA를 진행할 때 일반적인 네트워크 환경에서만 확인을 했는데, 의도적으로 3G 및 poor한 환경에서 진행을 해봤더라면 조금 더 빨리 이미지 개선작업을 진행할 수 있었을 것이라는 아쉬움이 남았다.
매번 빙의한다고 하는데 잘 안되는.... QA는.. 정말... 어렵다.
이미지가 중요한 역할을 한다고 판단되는 부분은 앱 내에서 크게 1. 이미지 슬라이드쇼
, 2. 개별 이미지
두 부분으로 나눌 수 있다.
1번과 2번의 유형에 따라 어떤 정책을 적용할지는 아래와 같이 결정되었다.
이미지 로딩 1개 이상 성공 시
1. 이미지 슬라이드쇼: 이미지 로딩에 성공한 이미지만 슬라이드쇼에 포함한다. 즉, 실패한 이미지는 노출되지 않음.
2. 개별 이미지: 성공/실패 여부 상관없이 모두 노출하되, 실패한 이미지 영역에 새로고침 버튼을 노출하여 유저가 다시 이미지를 불러올지 결정할 수 있도록 한다.
이미지 로딩 N개 모두 실패 시
1. 이미지 슬라이드쇼: 슬라이드쇼 영역에 새로고침 버튼 노출
2. 개별 이미지: 실패한 이미지 영역에 새로고침 버튼 노출
PM 및 프론트엔드 사수와 함께 논의한 끝에 위와 같이 정책이 정해졌고, 해당 부분을 위해 엔지니어로서 어떤 작업들을 진행해야할지 아래와 같이 정리해보았다.
pre-loading 적용
스켈레톤 적용 타이밍 수정
as-is
API가 Fetching 되는 동안 스켈레톤 노출
to-be
API가 Fetching 되는 동안 + API Fetching 후 이미지 url들을 pre-loading 하는 동안
로드에 성공한 이미지 url을 활영하여 base64로 인코딩하여 사용
이 부분은 우리 팀 스크럼 마스터이자 백엔드개발자인 팀원이 제안해주신 내용인데, 사실 이미지 url을 활용해 이미지 자체를 base64로 변환할 수 있다는 사실을 처음 알았다.... 모자란 내 지식에 다시 한 번 놀랐던........
조금 더 확실히 하기 위해 이 부분까지 적용하고 싶었는데 우선 url 자체로도 성공/실패 여부를 확인할 수 있기에 여기까지 적용하는 것은 진행되지 않았다.
그리하여 위와 같이 정리된(좀 더 깔끔한;;) 요구사항에 따라 타 팀의 시니어분께서 관련 hook을 만들어주셨다. 직접 진행하지 못한 부분은 아쉬웠지만 중요도가 높으면서 다른 플랫폼에서도 사용할 수 있어야 함이 목적이었기에 기본기가 탄탄하게 능숙한 시니어분께서 기초 작업을 진행해주셨다. 덕분에 Best Practice를 보고 적용해볼 수 있어서 좋은 기회가 되었던 것 같다. (작성해주신 코드를 보고 내가 직접 진행했으면 큰일났겠다는 생각이 들 정도로... 너무 잘 작성해주셔서 많이 배웠다......)
// 이미지 url을 인자로 전달하여 pre-loading 진행하는 함수
export const preloadImage = (url: string) => {
new Promise<string>((resolve, reject) => {
// 이미지 태그를 생성하여 해당 이미지 태그의 src 프라퍼티에 인자로 전달받은 url을 적용한다.
const imageElement = new Image();
const handleLoad = () => {
resolve(imageElement.src);
};
const handleError = (error) => {
reject(error);
};
// 이미지 성공, 실패했을 경우에 대한 handling을 추가하고 이미지 url 적용
imageElement.onload = handleLoad;
imageElement.onerror = handleError;
imageElement.onabort = handleError;
imageElement.src = src;
}).catch(error => {
// reject 되었을 경우 에러 핸들링
throw new ImageError( ... );
});
}