Node.js 에서는 아래와 같이 값을 전달받아 데이터베이스에 쿼리를 날려 검색을 하도록 하였다.
//--------------------------- 검색
app.get('/search/:name',(req,res)=> {
let sql = 'SELECT * FROM POSTS WHERE title REGEXP ?';
let params =[req.params.name];
connection.query(
sql,params,
(err, rows, fields) => {
res.send(rows);
}
);
});
만약 검색으로 '일'을 검색하였다면 돌아온 응답 값은 아래와 같다.
[{"id":15,"title":"일본이 전자 산업 분야에서 내수시장을 방어하는 방법","content":"일반 재단법인 일본 원자력 문화 재단에서 인용\n일본 전기의 주파수는 시즈오카 현의 후지 천 당을 경계로 동쪽은 50Hz, 서일본이 60Hz와 다릅니다.","date":"2020-03-10T15:00:00.000Z","views":99,"good":30,"bad":60,"pic_thumb":"/image/1f71317100b29d5250f418db15a7c700","tag_0":"일본","tag_1":"전압","tag_2":"시즈오카","tag_3":null,"tag_4":null},
{"id":23,"title":"일류를 꿈꾸는 삼류 조폭의 이야기","content":"송강호란 배우의 이름을 확실히 사람들에게 각인시켜준 작품이었음. 이후로 송강호는 한국을 대표하는 배우로 성장했지","date":"2020-03-11T02:24:54.000Z","views":54,"good":30,"bad":21,"pic_thumb":"/image/36127119c67709878706cdae88ef15e4","tag_0":"영화","tag_1":"송강호","tag_2":"기생충","tag_3":"한국인","tag_4":null},
{"id":25,"title":"핵무기가 만들어지면 벌어지는 일들","content":"첫번째 이유는 우방국의 핵우산, 두번째는 박정희 정부때 찌라씨로 만들고 있었다가 완성 직전에 들켜서 npt에 가입한 걸로 알고 있음","date":"2020-03-10T15:00:00.000Z","views":75,"good":30,"bad":15,"pic_thumb":"/image/fcd451dba2f33e30da8133428448a36e","tag_0":"한국","tag_1":"핵무기","tag_2":"박정희","tag_3":"대한민국","tag_4":null},
{"id":36,"title":"80년대 일본을 느껴보자 감성 시티팝 플레이","content":"버블 경제 당시 최고의 음향장비와 굉장한 녹음시설 그리고 최고의 인력들이 다시는 만들지 못할 음악을 만들어냈다","date":"2020-03-11T05:43:39.000Z","views":0,"good":0,"bad":0,"pic_thumb":null,"tag_0":null,"tag_1":null,"tag_2":null,"tag_3":null,"tag_4":null}]
포스트의 '일'이라는 문자가 포함되어 있기 때문이다.
위에서 받아온 값은 JSON형식이기 때문에, 클라이언트단에서 받아 각 필드들을 읽고 맵핑하여 구조체 안에 넣는 작업을 했다.
class Post {
final int postID;
final String title;
final String content;
final String date;
final String thumb;
final int views;
final int good;
final int bad;
Post(
{this.postID,
this.title,
this.content,
this.date,
this.thumb,
this.views,
this.good,
this.bad});
factory Post.fromJSON(Map<String, dynamic> json) {
return Post(
postID: json['id'],
title: json['title'],
content: json['content'],
date: json['date'],
thumb: json['pic_thumb'],
views: json['views'],
good: json['good'],
bad: json['bad'],
);
}
}
" 어플을 만들어보자! 라는 목표를 가진 시동맨이 있다고 하자. 시동맨은 이제 두가지를 떠올릴 것이다. 안드로이드 그리고 ios. 역시 ios보단 안드로이드가 쉬우니 안드로이드로 어플을 개발하기로 한다. 몇날 며칠 꼬박꼬박 밤을 새워 가며 짠! 하고 어플을 만들고 어플을 앱스토어에 올렸다. 어플의 성공을 기다리고 있던 얼마 후, 어플의 사용자인 김아무개는 '아이폰에는 없나요?' 라는 피드백을 올린다. 다섯 글자에 시동맨은 땀을 흘리기 시작한다. 그렇다. 이 어플은 안드로이드용 앱이기 때문에 아이폰에서는 쓸 수가 없는 것이다! 그래서 피드백을 반영해 똑같은 디자인과 똑같은 기능을 가진 아이폰용 어플을 Swift로 개발하기로 한다. 즉, 포팅(Porting)을 하기로 한다. 몇날 며칠 또 한번 꼬박꼬박 밤을 새워서 짠! ios용 어플을 개발하였다. 결국 어플을 하나 만드려고 각기 다른 언어로 싹 다시 만든 것이다! 심지어 ios용 어플을 개발하기 위해 거금을 들여 맥북까지 구입하게 되었다. 으악 :< 아니, 도대체 이 세상에는 한번의 코딩 작업으로 안드로이드 ios 환경에서 모두 실행 할 수 있는 뭐 그런 건 없는 것인가? "
플러터(Flutter)
플러터는 구글에서 개발한 크로스 플랫폼 모바일 앱 개발 프레임워크이다. 구글에서 만들었으니 당연히 사용되는 언어 또한 구글에서 개발한 dart 라는 언어를 사용한다. 한번 dart로 작성한 것은 안드로이드와 ios 환경 양쪽에서 실행이 가능하다. (물론 ios 시뮬은 맥북이 있어야 하지만... 그래서 내가 맥북 질렀다 쓰바)
나는 2020년 1월 중반부터 이 플러터를 사용하기 시작하였는데, 플러터를 사용하면서 느낀 장점을 써보겠다.
지극히 내가 느낀 장점이니 굉장히 주관적이고, 아마 빠진 부분이 많을 것이다.
1. UI Rendering
플러터에서는 기본적으로 각 플랫폼(Android, ios) 의 디자인을 그대로 제공한다. 즉, 안드로이드에서는 material 디자인과 ripple Animation 을, ios에서는 cupertino 디자인을 볼 수 있다. 즉, 플랫폼에 따라 디자인 가이드에 맞게 화면을 그려주는 것이다. 이것은 마치 네이티브 언어로 작성한 것 같은 착각을 불러올 정도로 기분이 좋다. 또한 프로토타입의 UI 앱 화면 그대로를 구현하는 것도 자유자재로 할 수 있었다.
2. Fast development
위에서 말했듯, 플러터는 dart라는 언어를 사용한다. 이전에 있었던 개발 경험(이라고 해도 거창한 게 아닌 대학교 과제)은 대부분 C언어나 자바로 개발하였다. 그래서 나는 새로운 언어인 dart를 배우는 데 어느정도 시간이 걸릴 것이라 생각했으나, 작은 어플을 하나 만드는 데 생각보다 오래 걸리지 않아서 놀랐다.
플러터에서는 위젯(widget)이라는 것이 있는데, 이 것의 사용법, 작성 구조만 파악한다면 자바와 같은 객체지향 언어 개발 경험이 사람은 아마 해가 떠서 해가 지기 전까지는 충분히 배울 수 있을 것 같다. 플러터는 개발 속도가 빨랐는데, 그 이유는 dart언어가 배우기 쉽다는 것도 있지만 플러터에서 hot reload를 제공한다는 것이다.
즉, 코드를 작성하거나 수정하면 그 즉시 에뮬레이터에서 실시간으로 바뀐 화면을 띄어준다. 덕분에 UI를 구현하는데 굉장히 간편했고 시간도 많이 절약할 수 있었다. (맥북에서는 VS Code로 개발 중인데 hot reload도 안되고 빌드도 안되서 실행은 Xcode에서 하는 중ㅜㅜ 아마도 안드로이드 스튜디오에서만 되는 듯.)
3. Flutter.dev, Youtube...etc
구글에서는 정리하고 알려주는 걸 참 좋아하는 것 같다. 플러터로 어플을 개발하다가 구글링을 해야하는 순간이 오곤 하는데, 그럴 때마다 구글에 검색하면 거의 90퍼 이상은 해결된다. 도움이 되었던 사이트는
나는 특히, 유투브로 많이 찾아 보았는데, 국내 유투버에서는 코딩파파(The Coding PaPa)님이 좋은 영상들을 올려주시는데 많은 도움을 받았다.
단점
플러터는 단점 또한 분명히 있었는데, 플러터로 개발하다가 디자인 부분이 아니라, 기능적 측면에서 구현을 하다보면 내가 원하는 기능을 구현하려면 어쩔 수 없이 네이티브 언어를 써야할 때가 존재하게 된다... 특히, 까다로운 작업을 필요로 하는 어플인 경우에는 플랫폼의 의존성이 크기 때문에 더욱이 그럴 것이다.
내 경우에는 휴대폰에서 갤러리 사진을 다중으로 선택하는 기능을 구현하는 것이였다. 사진 1개를 선택하는 기능 정도는 image_picker 라는 패키지를 사용하면 되었으나, 다중으로 선택하기 위해서 우선 갤러리에 있는 사진을 모두 gridview에 띄우려고 하였다. 그런데 용량이 큰 사진을 load 하면서 memory가 부족하게 되어 어플에 crush가 일어났다.
그래서 구글로 찾아보다가 gridview에 띄울 때에는 원본 사진의 용량을 줄인 thumbnail 사진을 써야 한다는 것을 알게 되었다. 그렇게 어떻게 사진을 압축해서 저장할까 찾아보다가 안드로이드 MediaStore thumbnail 을 사용하기 위해 네이티브로 작성하여 channel을 만들고 플러터와 연결하는 노가다를 했다. 플랫폼에 맞게 해주는 작업 또한 추가적으로 생긴 것이다. '근데 이럴꺼면 애시당초에 플러터를 안쓰지' 라는 생각에 다른 패키지를 찾아보다가 다중 선택을 지원하는 multi_image_picker 을 찾아서 쓰게 되었다. 이 패키지를 뜯어서 썸네일을 생성하는 부분만 사용하려고 했으나, 이 패키지 또한 안드로이드와 ios에서 채널로 연결되어 있어서 그냥 그대로 사용했다...
크로스 플랫폼에 대한 큰 기대를 하기는 아직 시대적으로 맞지 않나? 네이버 라인에서도 플러터를 이용해 어플을 만드려다가 결국 네이티브로 개발하였다라는 글이 있다. 여기
(역시 네이티브 언어가 답인가...)
앱스토어에 들어가 보면 하루에도 수백개의 어플이 올라와 install 버튼을 눌러달라고 한다. 하지만 사람들이 쓰는 어플은 정해져 있다. 인스타그램, 페이스북, 카톡... 3대장이다 즉, 사람은 자신이 평소 사용하는 어플만 쓰지 새로운 어플을 다운받아서 써보는 일은 손에 꼽는다는 것이다.
이런 현실 속에서 개발팀이 앱을 개발하면서는 굉장한 시간적, 금전적 비용이 들게 되는데, 플러터를 사용하게 되면 빠른 기간 내에 어플을 만들어 볼 수 있으며, 크로스 플랫폼이기 때문에 안드로이드, ios 두 가지를 개발하는 것 보다 비용 또한 줄어들게 된다. 위에서 말한 단점이 분명 존재하지만 총알의 갯수가 적은 스타트 업이나, 개인 개발자들에게 있어서는 좋은 프레임워크인 것 같다.
나는 올해 초부터 취업용 포토폴리오를 위해 플러터를 이용해 Optio라는 앱을 만들고 있다. 이 어플이 이후에는 맥북을 샀으니 두고 두고 Swift를 공부하게 될 터이기에 플러터를 쓸 일이 없을 것 같지만, 현재 개발하고 있으니 중간 중간에 알게 된 내용을 블로그에 적어 기록해 두려고 한다.