エンジニア向けのニュースアプリを作った【個人開発】

## 要約
- エンジニア向けのニュースアプリをFlutterで作った。
- 毎日Zenn、Qiita、noteやそのほか海外のテックメディアを開くのが面倒。
- RSSフィードで登録していくのもいいが面倒だし、時に不要な情報もある。
- 個人に最適化されたニュースを提供し、エンジニアの日々の情報収集を効率化させることを目的とした個人開発アプリを作ることにした。
- スマホアプリ開発言語はFlutter,バックエンド言語はPython、インフラはGCPのCloud FunctionsとFirebaseを利用。

## 背景と課題
わたしたちエンジニアは毎日チェックすべき情報が多すぎる。毎日Zenn、Qiita、noteやそのほか海外のテックメディアをひらいて、不要な情報の中で自分に関連するような情報を見つけて確認する作業をしているとあっという間に１時間が経過してしまう。おそらく、わたしたちが重要な記事に辿り着いて読んでいる時間は全体の6割程度だということに気づいた。ゆえに効率的に日々の最新のトレンドを押さえることは非常に重要だ。

## 目的
エンジニア向けのニュースアプリは意外と少ない。そして個人の状況に最適化する形でニュースを提供することがもっと改善できるような気がした。そこで私は、「個人に最適化されたニュースを届け、情報収集を効率化させる」ことをテーマにアプリ開発を行なった。

## 作ったもの：エンジニア向けニュースアプリ「MarkOne」
![](https://storage.googleapis.com/zenn-user-upload/14255e18e26a-20230118.jpeg)

https://apps.apple.com/jp/app/markone-%E3%82%A8%E3%83%B3%E3%82%B8%E3%83%8B%E3%82%A2%E5%90%91%E3%81%91%E3%83%8B%E3%83%A5%E3%83%BC%E3%82%B9%E3%82%A2%E3%83%97%E3%83%AA/id1553709153

## 機能

### ✨個人に最適化された記事を毎日配信
個人のフォローしたキーワードや、MarkOneでよく見られている記事のPV、ブックマークの数そのほかメタデータを利用することで個人に最適化された記事のレコメンドを行っています。

#### 使い方
1.フォロー管理画面でキーワードをフォローします
![](https://storage.googleapis.com/zenn-user-upload/28a558b3b305-20230119.gif)

2.フォローボタン押下した日の翌日からおすすめ画面で関連の記事がリマインドされるようになります
![](https://storage.googleapis.com/zenn-user-upload/5c8bc09ec058-20230119.gif)

### ✨多数のテックメディアの最新記事を確認できます
Zenn、Qiita、noteそのほか主要なテックメディアの最新記事を自動で収集し、定期的にお届けします。配信された記事は3日間表示されます。
(※こちらの機能はログインをしなくても利用いただける機能です。)
![](https://storage.googleapis.com/zenn-user-upload/a61a92d3c38b-20230119.gif)


### ✨記事のブックマークが可能です
気になった記事があればブックマークをして後で読み返すことが可能です。
この機能の利用には事前にアカウント登録をしてログインすることで利用できます。
![](https://storage.googleapis.com/zenn-user-upload/265fe7b613fe-20230119.gif)


### ✨記事の検索が可能です
ヘッドライン画面の左上の虫眼鏡ボタンから記事の検索が可能です。
キーワードを入力いただければ、全記事のタイトルを部分一致で検索してくれます。
検索スピードはなかなか高速です。
![](https://storage.googleapis.com/zenn-user-upload/8be6177d0d3c-20230119.gif)


### ✨MarkOne開発者からのお知らせを受け取れます
お知らせ機能を搭載していますので、MarkOne開発者からのちょっとしたお知らせをアプリ上で確認することが可能です。

## 実装について
もし今回の記事を見ていただいて「自分もニュースアプリ作ってみようかな？」と思っていだだけた方に向けて、効率的に開発をためのトピックスを紹介します。

### APIの呼び出しは最小限に
MarkOneでは、GCPのCloud Functionsに実装したPythonのアプリケーションが記事のスクレイピングを行い、取得した結果を一度FirebaseのFireStoreに格納しています。

このFireStoreに格納した結果、Flutter側でページを開くたびに参照するとあっという間にGCPの無料枠を超えてきます。

そこでFlutter側で1日に規定の回数、FirebaseのFireStoreから取得を行い、規定回数を超えた場合は、SQLiteによって構築されたモバイル側のDBから記事情報を取得するようにしています。

情報のリアルタイム性は失われますが、ユーザーのニーズへの影響は低いかと思います。何よりコスト面はかなり安くなります。

### ステート管理はRiverpod
ステート管理は「Riverpod」で行っています。一昔前よりもだいぶ品質が安定してきたのと、活用ケースの事例が増えてきたこともありだいぶ「イイやつ」になってきました。

Riverpodの使い所としてはViewModelとして使っており、表示する記事の状態管理として活用しました。

https://riverpod.dev/


### 記事の取得は基本RSS、どうしても取れない時のみスクレイピング
さて、おそらくニュースアプリの肝となるスクレイピングの部分ですが、MarkOneではRSSとスクレイピングを混合して記事の取得を行っています。

つまりRSSで記事が取得できるメディアはRSS。RSSで記事が取れないメディアはスクレイピングをしています。

全ての記事をスクレイピング前提で作り込むと、処理時間がとてもかかってしまうのと、取得元のサイトでデザイン変更などが行わた場合またスクレイピングの処理を作り直す必要性があり非常に保守コストがかかってしまいます。

そこでスクレイピングはできるだけしないように記事の取得を行っています。

ちなみにスクレイピングはPythonで行っているので、「BeautifulSoup」を使用しました。
https://www.crummy.com/software/BeautifulSoup/bs4/doc/

これで記事のタイトルとURLといった最低限の情報のみを取得しています。

### スクレイピングで取得した記事のカテゴライズは力技
スクレイピングで取得した記事は、一定の条件に従って「JavaScript」「HTML」といった形でtagが付与されるような形でカテゴライズされます。

本来であれば、記事の内容や、タイトルを自然言語解析し類似性の高いキーワードでカテゴライズするといった機械学習のアプローチをしたいところでした。

しかし、これではあまりにもリッチに作りすぎていつになってもサービスがリリースできないので、特定のキーワードがタイトルに入っているかのみをみて、カテゴライズをしています。

そうです、かなりの力技です。これを全ての記事に対し、100以上のキーワードを使って処理しています。(単純に10記事処理するのに10*100の処理が発生してしまう...。)


### 見出し画像はOGPを使う
開発当初は「よくあるキュレーションニュースアプリの見出し画像ってどうやってとってきているんだろう？」と思っていたんですが、OGPというhtml要素があり、これが活用できます。

ツイッターなどに記事をシェアすると、見出し画像が勝手に表示されるかと思います、あれば記事の元が事前にOGPに見出し画像のURLを仕込んでくれているからです。

そして大体のWebメディアにはこのOGPに見出し画像が設定されています。(たまにないこともある)

なのでスクレイピングをする際にこのOGPの要素を検索して、画像のURLを取得します。
つまり、先ほどのBeautifulSoupを使って以下のように実装すれば簡単に見出し画像を取得できます。

```
link = <スクレイピングしたいURL>
load_url = requests.get(link,allow_redirects=False)
soup = BeautifulSoup(load_url.text, "html.parser")
elems = soup.find_all('meta', attrs={'property': 'og:image'})
for elem in elems:
   imaglink = elem.get('content')
```

### MVPを明確にして、質にこだわる
「サービスを早く出したい」と焦ると、品質の悪いものを世に出すことになりかねないし、逆に質にこだわりすぎるといつになってもプロダクトがリリースできないなんてことがよくあります。

ここで大事にしたいのがMVPという考え方です。MVPとはMinimum Viable Productといわれ、「顧客が求める最低限のニーズを持つプロダクト」です。

顧客が最低限求めている価値を明確にし、そこから機能設計に落とし込みます。
そしてスコープを絞った上で徹底的に品質にこだわることが重要になります。

たまにMVPを決めて、早く出す(質は問わない)なんて方もいますが、個人的にはある一定品質が担保されていないと、ユーザーは興味も示さなければ、継続的に利用することもないかと思います。

また今後の開発コストについても、一定のルールを持って品質の高いコードを書いた方が生産性は上がり続けます。

なので、私自身の過去の失敗からMVPを決めたら、丁寧に作ることを意識して今回開発を行いました。


## 今後について
### アプリの機能改善を継続します
自分が最大の利用者となって、アプリの改善を継続して行っていこうと思います。またニュースの表示順番については安直な実装をしているしているため、よりユーザーの興味を持つ情報がページ上位に来るように調整をしていきます。

### ニュースアプリのプラットフォームビジネスに挑戦したい
実はこのアプリある程度汎用的に作っているので、他の業界のニュースアプリに作り替えることが可能です。例えばどこかの地域に限定したキュレーションニュースアプリにするといったような形です。
他にも似たような課題を抱えている業態がないか改めて調査し、新たなアプリ開発に着手するのも面白いかと思っています。

### アプリとビジネススキームの販売
前述したように、他業態でも転用できるアプリケーションなので、是非同じようなアプリを作って自身のビジネスを作りたい、拡大したい方がいればこの仕組みをパッケージとして購入いただき利用いただけないかと考えています。キュレーションニュースアプリを作りたい経営者の方がいれば是非ご連絡ください。

## まとめ
RSSをベースとしたニュースアプリはAPIの参照/更新/削除を満遍なく行いますので、初めて個人開発をする方に大変おすすめの教材です。是非この機会に挑戦してみてください。

Twitterやってるのでフォローよろしくお願いします。
最後まで読んでいただきありがとうございました。

https://twitter.com/kimura9438