ずっと家でアプリ作っていたい

業務効率化小ネタなど

明確な目標とは

最近の流行でもある「未経験からエンジニアへジョブチェンジ」。 現在私もその目標を達成するために日々アプリ開発を個人で行っている。 しかし最近どうも開発のスピードが落ちている。

理由は明らかで、「本業が忙しくなっている」からだと考えていた。 しかし最近どうも問題はそちらでは内容な気がしている。 理由はわからないが漠然と「忙しい」ということを理由にして 開発を先延ばしにしている気がする。

何日か考えて思い至った。 それは「転職をすることに対して明確な目標が自分の中で確立していない」こと。

なのでまずはそこから考えたい。

【Flutter】pubspec.yamlにおけるバージョンの明記方法

flutter

説明すること

Flutterでの開発における、パッケージバージョンの明記方法の読み方・書き方

明記方法

Flutterでは使用する外部パッケージの情報をpubspec.yamlファイルにて管理する。 この時にバージョンを記載する場合があり、一般的な記法とキャレット記法の 2種類の明記方法でバージョン管理ができる。

例として1.2.32.0.0 のバージョンを基準に記載する。 また[package名]にはパッケージが入る。 自身が用いるパッケージとそのバージョンに適宜読み替えること。

一般的な記法

[package名]: any

特にバージョン指定をしない場合に用いる。空白と同じ意味になる。 非推奨の記法とされている。

[package名]: 1.2.3

バージョンを厳密に指定する場合に使用する。 記載されたバージョンのみが使用される。 この場合は1.2.3が必ず使用される。

必ず必要な場合以外は、基本的に避けるべき。 他のパッケージの依存性を解消できなくなる場合があるため。

[package名]>=1.2.3

1.2.3以上のバージョンを使用する。使用することが多い

[package名]>1.2.3

1.2.3より大きいバージョンを使用する。1.2.3は使用しない。

[package名]<=1.2.3

1.2.3以下のバージョンを使用する。あまり使う場面はない。

[package名]<1.2.3

1.2.3より小さいバージョンを使用する。基本的にはこれを使用する

例えば1.2.3で大きな修正が加えられた場合、他のパッケージとの依存性に問題がある可能性があるため。

[package名]>= 1.2.3 < 2.0.0

1.2.3以上、2.0.0未満のバージョンが使用される。 こちらは後述のキャレット記法で簡潔に書ける。

キャレット記法

キャレット記法とはAsciiで表示できない文字を、表示できる文字で代替して表記する記法。 キャレットとは「 ^ 」のこと。

[package名]^ 1.2.3

これは先述した[package名]>= 1.2.3 < 2.0.0と同じ意味になる。 より詳しい説明としては、「一番左にあるバージョン番号は変えない範囲で許容する」。 ただしキャレット記法は若干わかりづらく、必要がない限りは一般的な記法を用いた方が 保守性も高いと思う。

Web開発の超重要用語『API』とは?【知識ゼロから理解】

f:id:chang_app_dev:20210207201841j:plain

目次

Web APIとは「Webサービス開発を効率化するツール」です

APIApplication Programming Interfaceの頭文字をとった言葉です。

Wikipediaなどを見てみると

ソフトウェアコンポーネント同士が互いに情報を やりとりするのに使用するインタフェースの仕様である。

と書いてあります。

ja.wikipedia.org

なのでWeb APIの説明は

Webにつながっているソフトウェアコンポーネント同士が互いに 情報をやりとりするのに使用するインタフェースの仕様である。

と言えそうです。

ただし全く知識のない方からすると「は?」という感じですよね。

ものすごく簡単にWeb APIを説明すると、『公開されているWebアプリの機能の一部を使用できるツール」』です。 つまり開発を効率化するツールです。

ただしこれでは若干抽象的なので、折角ならきちんと理解したいですよね。

この記事では

  • Web APIを使う理由
  • 構成要素
  • Web APIの具体例

を紹介します。 是非最後まで読んでWeb APIの理解を深めてください。

Web APIを使う理由

f:id:chang_app_dev:20210207204206j:plain

Webサービスを開発する際、「こんな機能が実装できたらいいな」 と思う時があります。

ただし自分達で全てを作るにはお金と時間がかかります。 一から全ての機能を開発していては効率が悪いです。

そこでもし使用可能な公開されているサービスがあれば、 使用することで開発期間を短縮できます。 既に稼働しているサービスは運用実績があるので、 セキュリティ面でも一から開発するよりも信頼できます

そこでWeb APIが登場します。

Web APIを利用することで、他のプログラムが提供している サービス機能の一部を自分たちのサービスでも利用することができます。

結果としてその機能を開発する期間を省略することができます

ここまで抽象的な話でしたので、もう少し具体的に説明しましょう。

【具体例】株価表示Webサービスを作る

f:id:chang_app_dev:20210207204829j:plain

例えば最新の株価を表示するWebアプリを作るとします。

この時、株価のデータをどうやって集めると効率的でしょうか?

例えば1分ごとに自分で全ての株価を調べて、データベースを更新するのでしょうか?

またはわざわざ株価が表示されるサイトをスクレイピングして情報を取得するのでしょうか? その場合、参照しているサイトの構成が変更されたら情報を取得できなくなるリスクがあります。

この様に、自分たちで情報を取得するというのはあまり効率が良くないことが多いです。

そこで株価を取得できるWeb APIを使用します。 そうすればプログラムを定期的に実行するだけで、 Webアプリに表示される株価が更新できます。

株価を取得することのできるWeb APIですとYahoo Financeなどがあります。 ドキュメントに記載されている手順でリクエストを出すことで、株価の情報を取得できます。

この様にWeb APIを用いて他のサービスを利用することで、 処理の自動化・開発の効率化が実現できるのです

ではWeb APIとは実際どの様な要素で構成されているのでしょうか?

Web APIの構成要素

f:id:chang_app_dev:20210207205617j:plain

ここでは簡単にWeb APIの構成要素について説明します。

基本的に登場する要素は以下の2つです。

  • クライアント(Web APIを使用する側)
  • サーバー(Web APIを提供する側)

クライアントはサーバーが決めた通信ルールに則ってリクエストを送ります。 この時使用したい機能や取得したい値を指定します。

リクエストを受けたサーバーは要求された情報を クライアントにレスポンスとして返します。

基本的なやりとりの流れは以上の様にシンプルです。

ただしセキュリティ面から、たいていのAPIはデータのやりとりの前に 認証作業等が入りますが、ここでは割愛します。

Web APIの「エンドポイント」とは

f:id:chang_app_dev:20210207210047j:plain

Web APIには必ずドキュメント(使い方が書いてある説明書の様なもの)が存在します。

そこでは度々エンドポイントという用語が登場します。

これはWeb APIを使用するためのURIです。

Web APIを使用する際には特定のコマンドを叩く必要があります。 その時にインターネット上ではサーバーを特定するためにURIを指定する必要があります。 Web APIではこのURIをエンドポイントと読んでいます。

ですのでエンドポイントという単語に出会ったら、 「このURIを使ってWeb APIを使うんだな」と思ってください。

Web APIの具体例

f:id:chang_app_dev:20210207210536j:plain

世の中には数え切れないほどのWeb APIが公開されています。

ここではそんなWeb APIの中でも日本で特に人気のAPIをいくつか紹介します。

Google Maps Geocoding

Google Maps Geocoding:ドキュメント (googlecloud) | Rakuten RapidAPI

地図を表示するアプリですと結構使われています。

地図表示機能を一から作成するというのはかなり大変ですので、まさにWeb APIを使うべき機能ですね。

ぐるなびレストラン検索

ぐるなびレストラン検索 API Documentation (gurunaviws) | Rakuten RapidAPI

Web APIを使うことで、ぐるなびに掲載されている飲食店の情報を取得できます。

ぐるなびは割と古くからあるサービスですので、掲載されている飲食店舗数も多く、利用価値の高いWeb APIと言えます。

またこういった情報を公開することで、飲食店の宣伝にも繋がりますね。

amazon-price

amazon-price API Documentation (ebappa1971) | Rakuten RapidAPI

国内で訳5000万人が使用していると言われるAmazonに掲載されている商品の価格などの商品情報を取得できます。

Google Translate

Google Translate:ドキュメント (googlecloud) | Rakuten RapidAPI

翻訳は現在Googleの一人勝ちという印象の分野ですが、そのGoogleの翻訳機能を使用できるのはすばらしいです。

翻訳などの機械学習で実装される機能は情報量が多くないと中々精度が上げられず、また実装難度もかなり高いと思いますので、翻訳機能を実装する際には積極的に使用したいWeb APIです。

Yahoo Finance

Yahoo Finance API Documentation (apidojo) | Rakuten RapidAPI

前述の説明でもチラッと出てきたWeb APIです。

株価や相場などを取得することができます。

この様にWeb APIには様々なものが公開されており、 サービスを実装する際には「公開されているAPIで使用できるものはないか?」 と考えることで開発効率を上げることができます。

まとめ

最後にこの記事で紹介した情報をまとめます。

Web APIについて理解は深まりましたでしょうか?

実際にWebサービスを開発する上でWeb APIの知識は必ずと言っていいほど必要になりますので、早い段階で身に付けて、開発を効率的に進めましょう!

【入門】Google Chrome Extension (拡張機能)でデータを保存する

f:id:chang_app_dev:20210202223130j:plain

はじめに

データの保存ができる様になると機能の幅がグッと広がります。

そこで今回はGoogle Chrome拡張機能のStorage APIを使用してデータを保存する方法をシェアします。

データ保存をするために使用するStorage APIとは

developer.chrome.com

Storage APIGoogle Chromeブラウザにデータを保存するためのAPIです。

Storageには

  • Sync
  • Local

の2種類の利用方法があります。

Sync

Syncは公式サイトの説明によりますと、

When using storage.sync, the stored data will automatically be synced to any Chrome browser that the user is logged into, provided the user has sync enabled.

When Chrome is offline, Chrome stores the data locally. The next time the browser is online, Chrome syncs the data. Even if a user disables syncing, storage.sync will still work. In this case, it will behave identically to storage.local.

と説明されています。

Syncとは「同期」という意味でして、その名の通りユーザーアカウントに紐付けてデータを保存します。ですので別のデバイスChromeブラウザにログインしていればデータは同期され利用することができます。

またオフラインの場合一旦データはLocalに保存されますが、他のブラウザからはデータにアクセスできません。 次回オンラインになった時、ユーザーに紐づいてデータが保存されます。

Local

Localは単純にブラウザ内の保存スペースにデータが格納されます。 ですので他のブラウザで同じユーザーを使用してもデータは同期できません。

「じゃあSyncの方がいいじゃん」と思うかもしれませんが Syncは容量が512バイトと結構小さいです。 一方Localは5メガバイト程度保存できます。

まとめると次の表の様な感じ。

Sync Local
他のブラウザでデータ利用 ×
オフラインでのデータ保存
保存上限サイズ(byte) 512 5 M

ご自身の用途に合わせて、保存形式を使い分けていきましょう。

完成品

f:id:chang_app_dev:20210207081256p:plain:w400

機能としてはtextareaに文章を入力してもらい、 「SAVE」で文章をブラウザのLocal Storageに保存、 「LOAD」でその値を読み出すというものです。

ソースコード

manifest.json

{
  "name": "one click copy memo",
  "version": "1.0",
  "manifest_version": 2,
  "permissions":[
    "storage"
  ],
  "browser_action":{
    "default_popup": "index.html"
  },
  "icons": {
    "128": "memo.png"
  }
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
  <link rel="stylesheet" href="style.css">
  <link rel="stylesheet" href="css/bootstrap.min.css">
</head>
<body>
  <div class="container p-0 bg-light">
    <div class="form-group ps-4 pe-4 pt-4 pb-4">
      <textarea class="form-control" id="textarea" rows="8" placeholder="input here"></textarea>
    </div>
    <div class="ps-4 pe-4 pb-4">
      <!-- <div class="btn btn-outline-primary" id="copy-button">COPY</div>
      <div class="btn btn-outline-danger" id="clear-button">CLEAR</div> -->
      <div class="btn btn-outline-danger" id="save-button">SAVE</div>
      <!-- <div class="btn btn-outline-secondary" id="add-button">ADD</div> -->
      <div class="btn btn-outline-secondary" id="load-button">LOAD</div>
    </div>
    <div>
      <p class="h-1" id="input-text"></p>
    </div>
    
  </div>
  <script src="main.js"></script>
</body>
</html>

main.js

document.getElementById("save-button").addEventListener("click", ()=>{

  var inputValue = document.getElementById("textarea").value;

  chrome.storage.local.set({"memo1": inputValue}, function(){ });

});

document.getElementById("load-button").addEventListener("click", ()=>{

  chrome.storage.local.get("memo1", function(result){

    document.getElementById("textarea").value = result.memo1;

  });

});

アイコンはお好きな物を使用してください。 僕は以下のサイトでメモっぽい奴を適当に選びました。

icooon-mono.com

コード解説

今回はSyncではなくLocalを使用しての実装になります。 ですのでSyncを使用してのデータ保存に関しては他の記事等を 参考にしてください。(基本的にはあまり変わりませんが)

データを永続化して保存する上で必要なのは manifest.json内のpermissionsです。

Storage APIなどのAPIは、使用する際にはAPIサーバーに クライアントが使用する旨を伝える必要があります。 そこでpermissionsにstorageと記述することで APIが使用できる様になります。

また実際の保存・読み出し処理は以下の様に行います。

データ保存

chrome.storage.local.set({"memo1": inputValue}, function(){ });

setメソッドを使用します。第一引数には保存するデータを オブジェクト形式で渡します。

今回ですと、キーがmemo1で値がinputValueになります。 inputValueは前述したtextareaで入力された値になります。 呼び出す際にはキー名で値を呼び出すので、データの中身が判別しやすい 名前だといいですね。

第二引数には保存の際に行う処理をコールバックで渡します。 今回は特に行う処理がないので空です。

データ読み出し

  chrome.storage.local.get("memo1", function(result){

    document.getElementById("textarea").value = result.memo1;

  });

getメソッドを使用します。第一引数には読み出すデータのキーを渡し、 第二引数には読み出した際に実行する処理をコールバック関数で記載します。

今回読み出す値のキーはmemo1です。

また第二引数のコールバックには、Storage APIの仕様として 引数に読み出したデータが渡されます。 読み出した値はオブジェクト形式で渡されますので、 キー名を指定して上げることで値を受け取ることができます。 今回ですと、result.memo1ですね。

最後に受け取った値をtextareaのvalueに渡すことで表示できる様になります。

まとめ

以上がStorage APIを使用してのデータ永続化方法です。 個人的な感想としては思ったよりも簡単に実装できたと感じてます。

重要なポイントはAPIを使用するためにpermissionsにstorageを記載し、 仕様書の通りに実装することです。 この実装の流れはStorageだけに限らずあらゆるAPIで同じですので、 是非APIを使い方に慣れていきましょう。

本記事がお役に立てたら嬉しいです。

【実践】Google Chrome Extension (拡張機能)で電卓を作成する

はじめに

現在Googleに公開申請中なのですが、電卓拡張機能を作成しました。 便利な機能(結果を1クリックでコピーできる)を実装でき、 初めてのプロダクトとしては中々良い物ができたと思っています。 公開され次第、Twitterとブログで紹介したいと思います。

さて、今回は電卓拡張機能を作成するにあたって僕が学んだことをシェアしたいと思います。 主に以下の内容について書きます。

  • 拡張機能を作る際の手順
  • 基本的な電卓の実装方法
  • 便利な機能(結果を1クリックでコピーできる)の実装方法

完成品

f:id:chang_app_dev:20210131104906p:plain:h300

画像の様な見た目の電卓です。名称は「Answer Copy Calculator」です。 無料で公開しています。 小数計算も可能で、基本的な機能は網羅できていると思っています。

特徴としては「Copy Answer」ボタンで計算結果をコピーすることができることです。

計算結果をコピーすることって意外と多い気がしたのですが、 既存のストアに公開されている電卓拡張機能では、コピー機能を持っている物が 見当たらなかったので作成しました。

作成にかかった時間は大体5〜6時間位でした。 一度ほぼ作りかけたのですが、デザインが納得できずに作り直したので結構時間がかかりました。

使っている技術としては

です。特にChrome APIは使用しておらず、シンプルな構成です。

学んだこと

拡張機能を作る際の手順

何かを作る際には共通することですが、作る際の手順によって 効率が大きく変わります。

気をつけていたのは「行き当たりばったりにコーディングしない」こと。 きちんと作成する物のイメージを作ってから実際にコーディングする様に心がけました。

具体的には以下の様な感じで作業を進めました。

  1. 公開されている既存の電卓をチェックして、「どんな機能があれば付加価値を付けられるか」を考える
  2. 実装する機能を決める(基本的に最低限で良い) 3. デザインを決める(極力シンプルに)
  3. 実装する機能のロジックを決定する(可能であればフローチャートなどを作っても良いかも)
  4. デザインをまず完成させる(classとidは無闇に増やさない)
  5. JavaScriptで動的処理を実装する
  6. デバッグ
  7. 公開手続き←今ここ

JavaScriptを早くいじりたくなりますが、まずはデザインをしっかり固めてからにしました。 その方が作業の切り分け(デザインと機能)ができるので個人的な感覚としては効率がよかったです。 またデザインをまず作り上げちゃうことで、安心感も出るのでストレスも少ないです。

基本的な電卓の実装方法

電卓の主な機能

まず電卓の機能を考えます。ざっと以下の様な感じでしょうか。

  • 数値ボタンを押すと、押した数値が表示される
  • 小数点を使うことで小数が表現できる
  • 四則演算ができる
  • 「=」を押して計算結果が求まる
  • 計算結果を引き継げる

詳細は割愛しますが、それぞれ以下の様に実装しました。

数値ボタンを押すと、押した数値が表示される

これはボタンのElementにaddEventListenerで実行処理を渡すことで実現します。

// 0を入力した場合
document.getElementById("0").addEventListener("click", ()=>{
  repeatFlag = false;
  addInput("0");
});

そして入力された値をレンダリングします。 このレンダリングですが、僕はまず表示する文字列を格納する配列を用意し、 そこにpushしていき、レンダリングのタイミングで[文字列を格納する配列].join(""); を行い1つの文字列に変換して画面に表示しました。 こうすることで数値と演算子(+ - × ÷)や小数点などの切り分けが簡単になります。

表示はupdateFomula()という関数を用意し、画面更新処理を一元化することで DRYなコードを目指しました。

// 画面更新
function updateFomula(){
  document.getElementById("fomula-text").innerHTML = fomula_list.join("");
}

小数点を使うことで小数が表現できる

配列に格納した文字列を数値にする際には、parseFloat()を使用。 基本的に数値は浮動小数点で扱いました。

実は今回作成した電卓は1未満の小数を作成する際には以下の表記両方OKにしています。

  • 0.5
  • .5

parseFloatの仕様で、どちらの文字列を渡しても正しく読み取ってくれるので この様な実装にしました。

ですので配列に小数点を追加する際には「一つの数値で小数点が2つ以上入力されない」 というバリデーションを実装すればOKです。 このバリデーションはフラグbanInputDotFlagで管理する様にしました。 小数点が入力されるとtrueになり、再度小数点は入力されない仕組みです。 (実際のコードではもっと細かいジャッジを入れていますが、長くなるので割愛)

// dot
document.getElementById("dot").addEventListener("click", ()=>{
  repeatFlag = false;
  if(!banInputDotFlag){
    banInputDotFlag = true;
    addInput(".");
  }
});

四則演算ができる

四則演算の演算子も上記の配列に追加する形にしました。 配列をforEachでループさせて、演算子が現れたらそれ以前の文字列を数値にキャストして 計算を行っています。

developer.mozilla.org

配列を扱う際には、forよりもforEach()map()を使用した方が シンプルに記述できる場合が多いです。

「=」を押して計算結果が求まる

「=」ボタンを押すことで計算結果を求めます。

実はこの処理の実装に一番時間がかかりました。判定する要素がかなり多いからです。 式は正しく入力されているか、再度「=」を押された際の挙動はどの様にするか... など考慮すべき点がかなり多いです。

こういった複雑になりがちな処理は、極力実装する前にフローチャートなりで 処理を確認してからコーディングを行う方が良いと思います。泥沼になるので...。

計算結果を引き継げる

実は電卓には、以下の様な機能が実装されている場合があります。

  • 「1 + 1」 と入力
  • 「=」を押す
  • 「2」が表示される
  • 再度「=」を押す
  • 2 + 1が内部的に行われ、「3」が表示される

上記例の機能を実装したかったので、計算結果を退避させ 連続で「=」が押された場合に対応できる様にしました。 こういった細かい仕様が電卓には意外とあります。

便利な機能(結果を1クリックでコピーできる)の実装方法

拡張機能の目玉である「1クリックコピー」機能です。 実は仕組みとしては単純でして、以下の記事に掲載されているロジックを使っています。

qiita.com

意外とコピーという処理は素直に実装できないので、若干の面倒臭さは感じましたが 先人の知恵を利用しました。

終わりに

今回はソースコードはあまり載せず、実装における僕の考えなどを書きました。 今後も便利な拡張機能を公開していきたいと思います。