Firestore 실시간 연동하기.. 하고 보니 왜 이렇게 헤맸을까 싶긴 하지만 정말 어려웠다. 30줄 남짓한 코드를 작성하기 위해 구글링만 이틀 했다. 개발을 시작한 이후 처음으로 꽉 막힌 기분이었다. 그래도 이번 경험을 통해 무작정 코드부터 작성하는 것보다 개념을 완벽히 이해한 후 코드를 짜는 것이 더 빠른 길이라는 것을 배우게 되었다. 길게 헤맨 이유는 4가지가 있다. 매우 빠른 버전 업데이트, 부족한 개념, 미숙한 구글링 실력, 그리고 무작정 코드 작성하기
iOS 개발할 때는 공식문서를 보거나 다른 분들의 블로그를 보면서 원하는 정보를 얻기 쉬웠다. 그런데 Flutter는 버전 업데이트가 매우 빨라 참고할 수 있는 정보의 양이 적었다. 몇 개월 전에 작성된 다른 블로그에는 더는 지원하지 않는 코드가 많았다. 그래서 공식 문서와 몇 안 되는 최근 블로그들을 보면서 공부했다.
Flutter는 공부한 지 고작 2주 지났고 Firestore는 처음 다뤄보았다. Flutter 개념이 잘 잡혀있지 않다 보니 Flutter로 Firestore를 다루는 것은 더 복잡했다. Firestore 공식문서는 기능별로 코드가 자세히 설명되어있다. 그런데 위젯 widget, 뷰 view 같은 기본적인 개념도 잘 모르다 보니 코드를 명확하게 파악하지 못했다. stackoverflow를 찾아볼 때도 비슷했다. 개념이 흔들리다 보니 답변 코드를 제대로 파악하지 못했다. 오류 답변을 보고 잘못 공부하고 있는 경우도 있었고 정답 답변을 눈앞에 두고도 다른 답변을 찾아 돌아다니는 경우도 있었다.
Flutter와 Firestore에 대한 이해가 부족하다 보니 무엇을 모르고 무엇을 찾아야 할지 감을 잡기 어려웠다. 그러다 보니 적절한 범위의 검색을 하지 못했다. single document data 또는 documentsnapshot 키워드로 검색하면 바로 나오는 내용이지만 Get data from firestore 처럼 두루뭉술하게 검색했다. 검색을 하면 할수록 모르는 내용이 늘어나고 오히려 알고 있던 개념까지 꼬이는 기분이었다.
검색 시간만 늘어나고 같은 문제에 묶여있자 코드를 빨리 완성해버리고 싶었다. 그래서 얕은 이해를 토대로 무작정 코드를 꿰어나갔다. 당연히 정확한 이해 없이 작성한 코드에는 무수히 많은 에러가 뒤따라왔다. 에러가 난 핵심 원인을 찾지 못하니 하나의 에러를 고치면 또 다른 에러가 생기는 에러 지옥에 갇혀버렸다.
에러 지옥에서 빠져나오기 위해 다시 위젯 정의부터 하나씩 차근차근 공부했다. 위젯의 역할을 공부하고, build 위젯을 공부하고, streamBuilder를 공부하고, snapshot을 공부하고, 비동기를 공부하고... 이렇게 차례대로 공부해나갔다.
2일동안 구글링하면서 파편화되어있던 개념들이 머릿속에서 정리되기 시작했다. snapshot를 가져오기 위해 stream이 필요했구나! documentsnapshot 이라서 query 코드랑 충돌이 일어났구나! 하고 퍼즐이 맞춰졌다. 그렇게 개념 공부를 끝낸 후 공식문서를 보니 코드의 의도와 동작 원리가 바로 눈에 보였다.
결과적으로 기능을 이어붙이고 수많은 오류들을 고친 시간보다 차근차근 기본 개념과 동작 원리를 공부하고 코드를 작성한 시간이 훨씬 짧았다. 길게 헤맨 4가지 이유를 관통하는 하나의 이유는 부족한 이해이다. 무작정 코드부터 작성하는 것보다 개념을 완벽히 이해한 후 코드를 작성하는 것이 더 빠른 길인 것 같다. 빠르게 가는 유일한 길은 제대로 가는 것이라는 교훈을 얻었다.
class _detailPageState extends State<detailPage> {
String _images = "대표 사진";
String _name = "카페 이름";
String _location = "장소";
Widget _bodyWidget() {
var size = MediaQuery.of(context).size;
DocumentReference _documentReference = FirebaseFirestore.instance
.collection('cafes')
.doc('ke2dkmpMTwTWcfdZPj0h');
return StreamBuilder(
stream: _documentReference.snapshots(),
builder: (context, AsyncSnapshot<DocumentSnapshot> snapshot) {
if (snapshot.hasError) {
return Text('Something went wrong');
}
if (snapshot.connectionState == ConnectionState.waiting) {
return Text("Loading");
}
_images = snapshot.data!['images'][0];
_name = snapshot.data!['name'];
_location = snapshot.data!['location'];
return SingleChildScrollView( ); // 생략
},
);
}