のんラボ

POSレジの本部機能について少し調査してみました(金銭編)①

2019/07/28 2019/07/28

はじめに こんにちは。株式会社スマレジでサーバーサイドエンジニアとして働いています。Nonです。 働くうちにふとしたきっかけで本部機能について調べてみようと思い、ここにまとめてみました。 多分この記事は第1部として投稿され、追加分として2,3が次に投稿されていくことでしょう。 内容のソースとしては、弊社従業員や僕の友達で業界経験がある人に触りを教えてもらったって感じです。あとはこういう機能あったほうがいいかもなんて想像も混じったりしています。 本部機能とは? 各支部の売上管理機能 売上集計 売上分析 各支部の会員管理機能 会員集計 会員分析 商品などのマスタ管理機能 商品情報の登録 商品情報の配信 在庫管理機能 日報・月報閲覧機能 人件費閲覧機能 ドキュメント(マニュアル等)配信機能 以上がパッと思いつく限り挙げることができる機能でしょう。 とても多いですね 機能が多すぎてとてもわかりません。 そもそも、こういう機能を使用する人たちのニーズを考えるといってもそういった業界経験は全く無い僕です。 なので、今回は業界の業態と金勘定について調べてみました。 協力して頂いた方々には頭が上がりません。この場を借りて感謝いたします。 業態 POSレジと関連する本部機能と考えたら何を考えるでしょうか?僕はコンビニでした。 いろんな場所のコンビニのレジを一元管理する機能ですよね。 今回、業態を区別する際、商品マスタに焦点を絞ってみました。 結論から言って、大まかに4種類ありそうです。 支部所属\業態同業態異業態 自社のみスマレジ大手メーカー 他社含むコンビニショッピングセンター 以下、その特徴です。 自社-同業態 自社で同業態の支店を持っている業態。支店すべてが同業態なので、メニューや商品を統一することができるのが特徴。 店舗をまたぐ売上を集計分析できれば十分。つまり一般的なPOSシステム導入のみでほとんどのニーズをカバーできそう。 自社-異業態 自社で異業態(衣服・飲食・スーパー)の支店を持っている業態。支店によって取り扱う商品が違うのが特徴。 商品マスタを統一することが難しく、前支店で同じ商品マスタを使用するとなると商品管理がとても大変。だからそれぞれ違うマスタを用意し、業態ごとに導入する必要が出てくる。 売上分析も当然違ってくるので、それらすべてをまとめる本部機能が必要。 他社-同業種 支店のほとんどが違う法人から成り立つ業態。取り扱う商品はほとんど同じだが、法人(オーナー)が違うのが特徴 コンビニの様にオーナーを持ち、それを本部である本社がまとめる。 商品マスタは同業態なので統一することができるが、法人(オーナー)が違うので、レジはそれぞれが契約し、導入する必要がある。これを本部である本社が管理するためには契約をまたいで管理する機能が必要。更にロイヤリティの支払いを管理する機能が必要。 他社-異業種 支店のほとんどが違う法人から成り立ち、かつ扱う商品が違う業態。それぞれの法人がそれぞれの商品を1箇所に集まって商売をするのが特徴 アウトレットモールなどの商業施設のように、支部に全てオーナーが存在し、業態も衣類・飲食など雑多な店舗が一つの本部のもとで経営をしている形態。 契約をまたいで、売上を集計できる機能が必要で、更に利益の入金や、家賃や歩合の請求明細などを発行する機能が必要。 こう見ると・・・ 色々ありますね。これに当てはまらない例もありそうです。 例えば、フランチャイズについて調べていると、「コンビニ型フランチャイズとそれ以外」みたいに大別されている本もありました。 売上・利益の勘定方法 次は金銭の勘定方法に注目してみましょう。 特に、本部機能を搭載する上で一番仕様を詰めていくべきショッピングセンター(以下、SC)について着目し、纏めてみました。 前提 やはりこれは色々な形態の勘定方法があるらしい。 前提として、計算式そのものを利用者に決定される仕様が一番である可能性がある。 大まかに種別を分けることはできるが、どの形態にも例外はあるらしい。 例えば、百貨店における高級ブランドショップなどがそうらしい。百貨店側は購買者獲得のために、人気ブランドを百貨店内に設置したい場合がある。(定かでは無いが家電量販店のAppleStoreなどもそれに当てはまるのか??) このとき、百貨店は誘致することで人気ブランド店を設置しているらしい。つまり、百貨店側の利益に挙げる計算が他店舗と違う可能性が十分にありえるということです。 これを踏まえて種類を分けてみましょう。 家賃計算方法は坪単価が主流らしいが、これも時と場合によりけりかもしれません。 完全固定型 例:)不動産 売上に関係なく、設定された坪単価(土地の価格)×面積分が家賃となる。 とあるビルの一角を店舗として借り受け、毎月一定の「家賃」を支払う方法。ビルの管理者の収入となる。一番一般的。 完全歩合型 例:)百貨店 百貨店に属する支部に対して歩合率を決める。その店舗の売上×歩合率が家賃(みたいなもの)になる。 百貨店を経営する法人の収入となる。 併用型 例:)SC 坪家賃(坪単価×面積)と、(売上-最低保証)×歩合の合計が家賃となる。 家賃分は必ず支払う必要はあるが、売上には最低保障が設けられ、一定金額以上の売上が無い場合は免除になる。 ここで少し違う業態の勘定方法にも注目してみました。それはフランチャイズです。 フランチャイズの勘定方法 オーナーへ経営ノウハウを教えてもらったり、商品を利用したりして、自身で経営をしながら業界の勉強をしていくというのが、フランチャイズ業態の主な内容です。 特に、人気ブランドの看板を利用することができるというのは大きいですね。 しかし、その対価にロイヤリティという使用料金みたいなものを請求されます。 ではの請求金額の勘定方法について見てみましょう。 売上歩合型 一番一般的。多くの業種で利用されます。 売上✕歩合割 その理由は支部の利益とは関係なく一定のロイヤリティを得ることができるからです。 粗利型 特にコンビニ業界で採用され、他の業種ではあまり見ないそうです。 粗利✕歩合割 定額型 ロイヤリティ料金が定められていて、それを毎月支払います。 家賃みたいな勘定方法ですね。 まとめ 業態と金勘定についてまとめてみました。 こう見ると色々な計算方法や、色々な契約手法があるようです。 これらすべてを賄う機能を搭載する必要が出てきそうですね。 本部機能ですから特に狙うべきなのはショッピングセンターとフランチャイズかもしれません。 搭載すべきと思った機能はここには書けませんが、一番身近なコンビニやアパレルだけを勉強するとショッピングセンター用の機能が疎かになり、逆もまた然り。という状況に陥ってしまうかもしれません。 料金請求管理機能は十分な時間を書けて設計していきたいものです。 最後に 個人的に売上分析にBIツールを実装できればかなり使えるんじゃないかと考えています。 ただこれも実装するとなると、全体が肥大化してしまうような気も。。。 まぁ、できることからコツコツと! 今回は僕の勤務先に関わるネタでした! 本部機能に関わる記事はまた追加されていくことでしょう。その時はよしなに。 参考 弊社協力者と友人(本当にありがとうございました。)

テスト駆動はテストのための手法ではない

2019/07/15 2019/07/15

テスト駆動開発(TDD)は死んだって記事 正直、開発手法などの記事については上辺をすくっただけなので、よくわかりませんが、TDDは時代遅れの開発手法ということなのでしょうか? しかし、 @t_wada さんのセミナーに参加して以来、TDDが気になって仕方ありませんでした。(ライブコーディングは手法の有用性を知らしめるのにいい手段ということもセミナーで思い知りました。) 当時の僕はかなりのレガシーコードを修正していて、この本に書かれている通り、リファクタリングをする際にかなりの不安をもって修正をしていたからです。 セミナーの内容を見よう見まねで、個人開発プロジェクトでTDDしていましたが、この際しっかり勉強しようということで、本を購入し、この記事にまとめたいと思います。 前提 この記事は テスト駆動開発 を読んで書いた記事ではありますが、下記のような注意点があります。 この本の丸写しではない。つまり、僕の個人的価値観や経験をまじえて、僕が噛み砕いた内容を記載しています。 TDDそのものの知識を得るためにはこの本を読むか、関連するTDDの本を見ることをお勧めします。 ここでの僕の価値観とは この記事 でも書いたように ユーザー>コード 速度→正確性の順で重要(正確性を軽視せよというわけではない) と考えています。 もちろんこれに反論があるエンジニアの方もおられるかもしれませんが、これはTDDという開発手法ですので、合う合わないあると思いますし、これが正解とも言いません。 始めに 「TDDはテスト技法ではない。」これはまえがきにも書かれています。 TDDについて議論しているコミュニティを見ると、「自動テストは有用だが...」「テストを通すことが重要だ...」と書き込まれていることが少々あるが、これはTDDの議論ではないと僕は思います。 TDDとは分析技法であり、この分析を通じて開発をスムースに進める手法だと思っています。 だから、TDDの真価は「テストを書くことで製品の品質を担保するため」や、「テストを通すため」ではなく、「コーディングやリファクタリングで生じる欠陥と不安を出来るだけ排除するため」で、「品質の担保」や「テストのクリア」はTDDの副産物であると考えています。 簡単に言ってしまえば、 エンジニアの不安を取り除くための開発手法 ともいえるのではないでしょうか? まえがきで、天才的なプログラマーにとってはこの手法はとてもまどろっこしく、遠回りで面倒とあります。 優秀なプログラマは最初から正しく綺麗で、確実に動くプログラムを書けるのですから、当然でしょう。 テストを最初に書くということは、「失敗を前提」にしているということなので、優秀なエンジニアにとってもは無用のものです。 しかし僕はとてもじゃありませんが、天才ではありませんし、僕の書いたコードでバグを作ってしまうということは沢山ありました。 凡庸なプログラマである僕にとってTDDは「安心できる」上に「着実に前進できる」手法であると思っています。 開発サイクル とても有名な3つの単語を書きます。TDDのマントラだそうです。 レッド:動作しない、おそらく最初のうちはコンパイルも通らないテスト1つ書く。 グリーン:そのテストを迅速に動作させる。このステップでは罪を犯してもよい。 リファクタリング:テストを通すために発生した重複をすべて除去する。 繰り返しになってしまいますが、凡庸な僕の頭の中で幼稚に翻訳した内容を書きます。 一番始めにテストコードを書く。このテストを通すプログラムはまだ書かれていないので当然テストはエラーで終了する。 とりあえずテストを通すためのコードを書く。テストはクリアするが、実装が「とりあえず」なので、汚いコード 文字通り、リファクタリングする。汚い、つまりとりあえず書いたコードを綺麗な実装にする。 https://blog.ippon.tech/a-roadmap-to-tdd-adoption/ から引用 テストが意味するもの TDDのテストとは、もちろんテストコードの事を指しますが、テストを書くことで、仕様チェックをしているとも受け取れます。 テストコードを書くことで、思いつかない様な仕様バグを発見出来ます。 テストを書くということは仕様を満たすコードを書くということにつながるので、「仕様をプログラムコード」にするという作業になります。 少しだけ毛色が違いますが、 このサイト のおっしゃることも腑に落ちました。 レッド:仕様設計レビュー グリーン:探索テストレビュー リファクタリング:保守性レビュー http://kokotatata.hatenablog.com/entry/2015/03/05/120318 から引用 僕はTDDは開発手法であるといいました。この方もアジャイル開発手法としてTDDを利用しているみたいでした。 歩幅 この本には歩幅という単語が頻繁に出てきます。 歩幅というのはサイクルの粒度を指します。 期待する値、仕様を満たすテストを先に書き、とりあえず実装し、綺麗にしていく。この粒度は個人や開発部分によって粒度を変えるてよいとあります。 当然、1発でクリアしてもいいですし、難しい所ではコードを変更するたびにチェックしていくのもいいです。 例えば、ボールの個数をユーザーに均等に割り振って、そのあまりを返すロジックがあったとします。 この時、テストはこのようになるでしょう。 /** * test getRemainder method */ public function testGetRemainder() { $sample = new Sample(3, 2); $this->assertEquals(1, $sample->getRemainder()); } この実装は簡単なので、経験のある方ならすぐにゴールまで行けるでしょう。サイクルなど必要ありません。 class Sample { protected $ballNum; protected $userNum; public function __construct($ballNum, $userNum) { $this->$ballNum = $ballNum; $this->$userNum = $userNum; } public function getRemainder() { return $ballNum % $userNum; } } 上記のようにすぐにゴールまで、たどり着くことができるでしょう。 簡単な実装なので、エンジニアは不安も抱きませんし、仕様も簡単なので、答え合わせも簡単です。 この状態が歩幅が大きいと言えます。ゴールまで1歩でクリアしていくということですね。 仮にこの処理が実装の難しい箇所と想定したときの話をしましょう。 実装が難しく、エンジニアは不安を抱えています。仕様も理解しやすいとは言い難く、所謂「仕様がふわふわしている」状態です。 ここの歩幅は細かくするといいでしょう。 サイクルを頻繁に回す、つまり歩幅を小さく細かく実装していくことで、チェックを頻繁にし、エンジニアの不安を解消し、仕様の理解を助けます。 /** * test getBallNumPerUser method */ public function testGetBallNumPerUser() { $sample = new Sample(); $this->assertEquals(1, $sample->getRemainder()); } とりあえずテストを実行してみましょう。 この状態でテストを流すと、SampleクラスもgetRemainderメソッドも存在しないので、エラーが発生します。 これがレッドですね。 これをすぐに解消するために、中身を実装しましょう。 一歩目は下記のように実装しました。 class Sample { public function getRemainder() { return 1; } } テストクリアです。 とりあえずプログラムは動作します。 しかし、こんなプログラムに意味はありません。 有用な処理にするためにリファクタリングしましょう。 ボールを均等に配布した結果、あまりの数を出力するのですから、ボールの全ての個数をユーザー数で割り算し、そのあまりを出力すればいいですね。 class Sample { public function getRemainder() { return 3 % 2; } } テストクリアです。 とりあえずプログラムは動作します。 しかしこれではボールの数が3つ固定で、ユーザーの全体数も2で固定されています。 これも有用とは言えません。 もう一度リファクタリングしましょう。 ボール数とユーザー数を格納する変数を用意したらいいですね。 class Sample { protected $ballNum = 3; protected $userNum = 2; public function getRemainder() { return $this->ballNum % $this->userNum; } } テストクリアです。 しかしこれでは固定値の問題をクリアできていません。 コンストラクタで値を設定してあげましょう。 class Sample { protected $ballNum; protected $userNum; public funcion __construct($ballNum, $userNum) { $this->ballNum = $ballNum; $this->userNum = $userNum; } public function getRemainder() { return $this->ballNum % $this->userNum; } } テストクリアです。 可変数で計算結果を取得できるようにもなりましたし、リファクタリングはここまでとしておきましょう。 (もちろん、入出力バリデーションなど、バグを生む実装ですが、ここではあえて触れていません。気になる方はTDDで続きを実装しても面白いかもしれませんね。) これで最初に書いた実装と同じ実装になりましたね。 ここで何が言いたいかというと、 個人の技量 設計の複雑さ 実装時間の制約 さまざまな理由によって歩幅は変えることができるということです。 TDDが受け入れがたい方の意見の1つにこんなものがあります。 なにか実装を変更するたびに、後ろを振り返ってチェックする。 しかも大量に実装されるであろうテストコードをだ。 これは時間の無駄だし、効率が悪い。 僕もそう思います。 大きなプロジェクトになってくるとテストを流すだけで、何十分、何時間と取られますし、明らかにクリアできるコードをテストするのは効率が悪いです。 しかし、TDDは歩幅の調節ができます。 明らかに無駄、明らかにテストクリアできる実装だとわかっている場合は歩幅を大きく取ってしまえばいいのです。 TDDはエンジニアの不安を取り除く開発手法です。 テストをクリアするためのものではありませんし、品質を担保するものでもありません。 不安がなければテストしなければいいのです。 不安が出てくれば歩幅を小さくとって、何回も振り返り、チェックをしましょう。 テストと「対話」する TDDとの大きなメリットを感じる1つの考え方です。 これは本に書いてあったか忘れてしまいましたが、僕はTDDはテストと「対話」する開発手法だと考えています。 不安を感じたらテストと相談する プロジェクトに限らず、何かに不安を感じたら、人は他人に相談することでしょう。 それと同じように、仕様や実装に不安を感じたらテストに聞いてみましょう。 テストコードの実装に苦労したり、テストコードの実装中に明らかに仕様バグを生む設計である可能性を消すことができます。 テストを一度書いたらそれでFixでは無い 前章で「歩幅」について書きました。テストコードを書いて、実装します。このサイクルが細かいというのは、機能毎という意味もありますが、1機能単位でもありえます。 テストコードを書き実装した結果、 テスト内容が未熟であることに気づく 該当箇所のテストコードを修正している間、該当箇所の仕様バグを発見 仕様バグを修正する実装 ・・・ 僕がTDDで実装していると、上記の感じで実装の進捗とともにテストコードもだんだん良くなっていく現象がありました。 この現象がとても良く、テストコード実装=仕様確認をしている時間となります。 設計書とにらめっこしているよりもよほど有意義な時間となりました。 実際の工数について 工数は明らかに増える 工数は明らかに増えます。2倍くらいになります。当然です。テストコードは仕様の実装確認を示すコードですから実装分だけテストコードも増えます。 しかし、体感工数は少なくなります。 体感工数=ストレス 体感工数とはストレスだと考えています。 明らかに物理時間が伸びているのに何故かというと、「出戻り」が格段に減っています。 仕様確認をテストコードを書く時間に行っているため、 実装する前に仕様的なバグなどに気づくことができます 従来の方法で実装していると、実装してから気付いて、また実装・・・という悪循環です。 TDDの場合は、それは限りなく少なくなるので、実装時間が伸びますが、その分「確実に進捗が出ます」。 これはエンジニアのメンタルに非常に優しいです。 まさに「エンジニアの不安を取り除くための開発手法」といえます。 最後に 最後の方は少し駆け足気味になってしまいましたが、僕のTDDに対する感情をつらつらと述べてみました。 実務的な記事も今後書いていこうと思いますが、正直 個人によってTDDが合う、合わないはある と思います。 皆さんも一度お試しになって、実務で導入するかどうかを決めたほうが良いかもしれませんね。 .

MySQLでの高速化の基礎①

2019/07/05 2019/07/05

SQLの高速化の基礎 こんにちは。Nonです。今回はありそうでなかったSQLの高速化の基礎について記載します。 実は今まで触れる機会が少なかった 個人的にSQLが遅くて困ったことが無い(規模の小さい商品や、個人開発などのみかかわってきたもので・・・)ので、知らないこと多かったんですよね。 僕の経験で言えば、多くても5万くらいのデータしか扱ってきませんでした。 実はもっとデータの量もあったかもしれないけど、それは先人たちがすでに高速化していたものを使いまわしていただけだったと思います。 最近、データの量が多い画面を担当することになって、この知識があるかないかで、ユーザーへの便利度が決まるということに気づきました。 なので、備忘録ついでに書いておくことにしました。 EXPLAIN 高速化といえばまずこれ。インデックスが適切に使用されているかなど、MySQLがどのように実行するかの情報を見ることができます。 EXPLAIN SELECT * FROM users WHERE user_id = 1 typeを確認 type内容 constPRIMARY KEYまたはUNIQUEインデックスのルックアップによるアクセス。最速。 eq_refJOINにおいてPRIARY KEYまたはUNIQUE KEYが利用される時のアクセスタイプ。constと似ているがJOINで用いられるところが違う。 refユニーク(PRIMARY or UNIQUE)でないインデックスを使って等価検索(WHERE key = value)を行った時に使われるアクセスタイプ。 rangeインデックスを用いた範囲検索。 indexフルインデックススキャン。インデックス全体をスキャンする必要があるのでとても遅い。 ALLフルテーブルスキャン。インデックスがまったく利用されていないことを示す。OLTP系の処理では改善必須。 インデックス 高速化といえばまずこれ。 簡単に「インデックス」といいますが、結構扱いに困るイメージです。 知っているようで知らない感じに陥りそうな困ったちゃんです。 単純なインデックス SELECT * FROM articles WHERE id = 1 idは当然PRIMARY_KEYでAUTO_INCREMENTなので、検索が早いです。 イメージとしては辞書の「あ/か/さ/た/な/は/ま/や/ら/わ」の索引のイメージ。 範囲を扱うインデックス SELECT * FROM articles WHERE post_datetime BETWEEN '2019-04-01' AND '2019-05-01' AND user_id = 1 このときはpost_datetimeとuser_idに複合インデックスを作成しておくと早くなる。 でもこの例では一つだめなところがある。 インデックスの順番 post_datetimeで検索するよりも先にuser_idで検索される箇所から検索したほうが早い。 SELECT * FROM articles WHERE user_id = 1 AND post_datetime BETWEEN '2019-04-01' AND '2019-05-01' 正しくはこう。 post_datetimeはrange検索なので、あとから検索したほうが早くなる。 インデックスを貼る順番にも注意。 user_id post_datetime だ。 インデックスを使わない選択肢 SELECT * FROM memo WHERE delete_flag = false メモの削除件数0件。 このとき、インデックスがあろうがなかろうがフルスキャンである。 こういったインデックスの恩恵を受けられないカラムにはインデックスを貼らない方がいい。 インデックスを貼ると、INSERTの負荷が重くなるからだ。 (adsbygoogle = window.adsbygoogle || []).push({}); JOIN JOINするときはできるだけ絞れ。 JOINはループ 下記は例。(いい例が思いつかずすみません。) SELECT * FROM articles LEFT JOIN comments ON comments.articles_id = articles.id AND comments.articles_id = 1 WHERE articles.id = 1 JOINする対象テーブルは予め小さくしておく。 AND comments.articles_id = 1の箇所がそうです。 JOINをするときMySQLは内部的にループを回して条件を絞り込む。 例えば、ON comments.articles_id = articles.idの箇所、あっているものをループで検索しだす。ということは予めループされるものを小さくしておけば、検索までにかかる時間は短くなる。 phpで例を挙げると // join処理① for ($i = 0; $i < 1000; $i++) { for ($j = 0; $j < 1000; $j++) { } } // join処理② for ($i = 0; $i < 100; $i++) { for ($j = 0; $j < 100; $j++) { } } ①より②の方が早いに決まっている。 EXISTSという選択肢 SELECT * FROM articles WHERE EXSITS ( SELECT 1 FROM comments WHERE comments.articles_id = articles.id ) EXISTSは存在を確認するのみなので、早い。デメリットとして、EXSITSで書いたテーブル情報を参照することはできない。例ではコメントの有無はわかるが、コメントの内容を参照できない。 その他 数件程度ならパフォーマンス的にも問題が無いが件数が増えていくほどに効果が増していく系。 ちゃんとバッククォート「`」を記載する。 SELECT * FROM `articles` WHERE `articles`.`id` = 1 指定された型を意識する SELECT * FROM `users` WHERE `name` = '007' /* 007という名前でも検索は文字型で */ 最後に 疲れた・・・ いざ書き出したらキリがないですね。これ。 記事をあとから更新するか、分割するかします。お疲れ様でした。 また更新しますのでタグ検索など利用して見てください。

僕がVueで使用している便利パッケージを教えます!

2019/06/28 2019/06/28

Vueで使える!便利なパッケージ一覧 最初に これ、ちゃんと一つずつ説明しながら記事にしたい。 なので、この記事はとりあえず作成したみたいな感じです。 Vue-CropperJs vue-cropperjs A Vue wrapper component for cropperjs. Latest version: 5.0.0, last published: 2 years ago. Start usi... 前に書いたCropper.jsのVue版ですね。 Vueはラップするのも得意なので、こういうバニラで書かれたライブラリをVue化するというプロジェクトは結構見かけますし、多いですね。 似たようなラッププロジェクトが存在しますので、用途によって使うものを選択すればいいですよ。 Vue-Google-AdSence vue-google-adsense Vue.js Google Adsense Component with InFeed and InArticle Ads support. Latest version: 1.10.1, last ... これは今年の抱負メーカーの記事で少し触れましたね。 Vueを導入すると、Vueの中にプレーンなjavascriptを記載することはできますが、外部スクリプトを記載(WEB上で読み込んだり)は怒られてしまいます。そこで、このプロジェクトができたのでしょう。 <!-- Google Ads --> <div class="text-center"> <Adsense data-ad-client="ca-pub-5315745554235923" data-ad-slot="6372572820" data-ad-format="horizontal" ></Adsense> </div> こんな感じで広告表示をすることができます。 vue-tags-input GitHub - JohMun/vue-tags-input: A tags input component for VueJS A tags input component for VueJS. Contribute to JohMun/vue-tags-input development by creating an acc... これはタグ機能の操作に便利。 簡単に言えばQiita風にタグ付けができるようになります。 これのおかげで記事を書くのも簡単です。 toast-ui/vue-editor TOAST UI :: Make Your Web Delicious! TOAST UI is an open-source JavaScript UI library maintained by NHN Cloud. ご存じですか?? とんでもない量のUIを作成し、配布しているプロジェクトなんですが、この中にめっちゃくちゃ優秀なMarkdownエディタが存在します。 GitHub - nhn/toast-ui.vue-editor: This repository is DEPRECATED! GO TO 👉 https://github.com/nhn/tui.editor/tree/master/apps/vue-editor This repository is DEPRECATED! GO TO 👉 https://github.com/nhn/tui.editor/tree/master/apps/vue-editor... toast-uiのページ言ってDEMO触ってきたらわかる。 やばい。しかもそれをVueに落とし込む始末。 そのうち有料になりそうで怖いですね。 bootstrap-vue https://bootstrap-vue.js.org/ https://bootstrap-vue.js.org/を見る これはかなり有名ですね。Bootstrapで書かれたコンポーネントを簡単に呼び出す事ができます。記述量が多くなってしまいがちでしたが、この子のおかげで完結にまとまりますね。 少し前まで、日本語入力のバグがありましたが、それも解決されているようです。 Vuetify https://vuetifyjs.com/ja/ https://vuetifyjs.com/ja/を見る これもかなり有名。マテリアルデザインがすごい使いやすい。PWA向きですね。 でも、正直そこまで詳しくはない。 最後に Vue-CropperJs toast-ui/vue-editor vue-tags-input についてはそのうち時間ができたら纏め直そうと思う。 本当に便利なので、今後もお世話になりそうですし、宣伝しておきたい。 こういうの嫌う人もいるけど、効率化を本気で求めるなら、できている物は使わないとね。

Squidの注意点

2019/06/21 2019/06/21

Squidを使用するときにはここに気をつけろ! 皆さんこんにちは。Nonです。 実は私、Qittaにもしばしば投稿しておりまして、そちらがここになります。 ある時、Squid使用中に、ハマったことがありまして、今でもちょいちょいハマる場所なので、備忘録ついてでに書いておくこととしましょう。 ちなみにQiita記事はこちら 結論 if (nt == NULL) /* empty line */ continue; *nt = '\0'; /* null-terminate the address */ debugs(1, 5, "etc_hosts: address is '" << addr << "'"); lt = nt + 1; SBufList hosts; 一応念のためと思って squid のソースを読んでみたら、 なんと squid は libc を使わず独自に /etc/hosts を parse していて、 そこでは行頭にスペースやタブがあると、アドレスが書いてないものとみなされてしまうコードになっていました。 この辺です: https://github.com/squid-cache/squid/blob/d429cbd0e4d86d4af54ed50e499da14039ff7429/src/tools.cc#L954 これはビックリ。 というわけで、行頭のスペースないしTABが squid 限定で犯人でした。 この回答くれた方には恩しか感じません。僕は完全にSquidの設定ばかりを疑っていました。 注意点 文字コードや、改行ではない。 文字コードに依存する文字がhostsの中に記述されていれば関係あるかもしれません。 しかし、hostsは基本的に英数字しか書きませんので、問題ないかと。 なんかいい方法ないですか?? 自作アプリでローカルWEBサーバーにアクセスする際、Squidでリバースプロキシ立てちゃう方法をよく使用します。 この手法してるとあらぬトラブルに巻き込まれるので、なんかいい方法ありませんか? ちなみに、エミュレーターで無理くりするあの感じが嫌なので、実機を使用しています。 最後に ちょっと短いけど今日はここまで。 たまには過去の資産をまとめることも悪くないですね。 こういうリメイク記事も作成していくかもしれません。 にしてもコード読んで解決とは・・・世の中にはすごい人がたくさんいますね。

Z250での冒険日記

2019/06/14 2019/06/14

定期的にこんな感じの記事も追加して行くと思う。 4月27日〜29日 西日本一周ツーリング これはお友達と弾丸ツーリングに行きましたZXR1200のパワーを見せつけられましたね。 鳥取砂丘 写真は撮影してないけど、ジャリジャリ道ちょっと怖かった。滑るか心配だったね。 ここは大阪から近いので、何回も行ったことがあったけど、何回来ても楽しいですね。 今回の冒険ではメインディッシュじゃないので、早々に退散。 日本海を眺めながら こっち側は天気が荒れますね〜。日本海の波もいい荒れ具合。いい写真が取れました。 濡れたZが一番かっこいいんだよ・・・ 人生に一度は言ってみたい場所ランクイン 秋吉台カルストロード 完全に日本じゃない。別世界でしたね。 【絶景ロード】 秋吉台カルストロード ー山口県ー - 【公式】BikeJIN(培倶人|バイクジン) 角島大橋 あいにくのお天気でしたが・・・ 5月4日〜6日 能登半島一周ツーリング こちらもお友達と金沢へ。道中危険なこともありましたが、とても楽しかった。 東尋坊 火サスできそう・・・ 能登半島先端「狼煙」 ちょっとかっこいい 【道の駅 狼煙】公式サイト 〜能登半島さいはて、大浜大豆の地豆腐〜|石川県珠洲市 能登半島西側某所 サンセットが美しい。ふと見たときに、バックミラーに写り込んだので撮影。 5月26日 曽爾高原 いつもの いつメン 空気が美味しい 中学生の林間学校中でした。 最後に バイクはいいぞ! インプットの多くて、オフィスワークに偏りがちなプログラマーという職業にはピッタリじゃないでしょうか!! .

自分のサイトをサクッとPWA化!PWA導入編①

2019/06/07 2019/06/07

PWAを簡単に導入するには? 最近のWEB言語界隈は流行り廃りが非常に激しいですよね。 でもこのPWAはまだまだこれからな技術!導入したい誰かのために、導入方法を簡単ではありますが、記載しておこうと思います。 基礎知識として ServiceWorkerご存知でしょうか? こちらGoogleのブログです。 Service worker overview - Chrome Developers An overview of service workers. このページにはこう記載されています。 Service Worker の紹介 リッチなオフライン体験、定期的なバックグラウンド同期、プッシュ通知など、これまでネイティブアプリを必要としていた機能が Web にもやってきます。 Service Worker はそれらの機能を提供する基盤技術です。 Service Worker とは Service Worker はブラウザが Web ページとは別にバックグラウンドで実行するスクリプトで、Web ページやユーザーのインタラクションを必要としない機能を Web にもたらします。 既に現在、プッシュ通知やバックグラウンド同期が提供されています。 さらに将来は定期的な同期、ジオフェンシングなども導入されるでしょう。 このチュートリアルで説明する機能は、ネットワーク リクエストへの介入や処理機能と、レスポンスのキャッシュをプログラムから操作できる機能です。 「Service Worker はブラウザが Web ページとは別にバックグラウンドで実行するスクリプトで」この一文がキモですよね。 要はWEBページ開いて無くても、バックグラウンドで特定の処理をしてくれるということです。ブラウザ立ち上げてないのにプッシュ通知受け取ってくれたりするのはこの子のおかげです。 manifest.jsonご存じでしょうか? お次はこちらの公式サイト manifest.json - Mozilla | MDN manifest.json ファイルは、WebExtension API を使う拡張機能に必ず含めなければならない唯一のファイルです。 要はこのWEBアプリの基本属性の情報をためておくファイルですね。 テーマカラーは青で・・・アプリ名は〇〇で・・・アイコンは〇〇.pngで・・・みたいな情報を格納するファイルがmanifest.jsonです。 ちなみにこのサイトのmanifest.jsonは簡単な構成です。 { "short_name": "non's Labo", "name": "non's Labo", "display": "standalone", "icons": [{ "src": "android-chrome-512x512.png", "type": "image/png", "sizes": "48x48" }, { "src": "android-chrome-512x512.png", "type": "image/png", "sizes": "96x96" }, { "src": "android-chrome-512x512.png", "type": "image/png", "sizes": "192x192" } ], "start_url": "/" } この構成ファイルをもとに、PWAとしてインストールする情報になっています。 上図に乗っているアイコンが、アプリアイコンとして使用され、Name属性がアプリ名として、アイコンの下に表示されます。 導入するにはこの子達の設定をすればいいだけ 読み込むべきファイルを用意します。 manifest.json{ "short_name": "non's Labo", "name": "non's Labo", "display": "standalone", "icons": [{ "src": "android-chrome-512x512.png", "type": "image/png", "sizes": "48x48" }, { "src": "android-chrome-512x512.png", "type": "image/png", "sizes": "96x96" }, { "src": "android-chrome-512x512.png", "type": "image/png", "sizes": "192x192" } ], "start_url": "/" } sw.js var urlsToCache = [ '/js/app.js' ]; self.addEventListener('install', function (event) { return install(event); }); self.addEventListener('message', function (event) { return install(event); }); const install = (event) => { return event.waitUntil( caches.open('laboCache') .then(function (cache) { urlsToCache.map(url => { return fetch(new Request(url)).then(response => { return cache.put(url, response); }); }) }) .catch(function (err) { console.log(err); }) ); } self.addEventListener('activate', function (e) { console.log('ServiceWorker activate') }) self.addEventListener('fetch', function (event) {}) 導入したいTOPページにこれを記載 <script> // PWA window.addEventListener("load", () => { if ("serviceWorker" in navigator) { navigator.serviceWorker .register("/sw.js") .then(registration => { console.log("ServiceWorker registered"); registration.onupdatefound = function() { console.log("Exist update"); registration.update(); }; }) .catch(error => { console.warn("ServiceWorker error", error); }); } }); </script> 同様にheadタグ内でmanifest.jsonを読み込み <!-- PWA --> <link rel="manifest" href="/manifest.json"> 解説 sw.jsについて sw.jsこれはなにかというと、WEBページがアクティブじゃないときに走る処理です。 // インストールされたとき self.addEventListener('install', function (event) {}); // アクティベートしたとき self.addEventListener('activate', function (event) {}); など、様々なイベントを検知して、バックグラウンド実行してくれます。 他にもイベントはたくさん用意してありますし、これ用のサードパーティ製ライブラリも存在します。 私達はこれを駆使してオフライン対応や、通知イベントを発火したりします。 上に書かれているような内容ではconsole.logでログ吐き出しているので、オフライン対応もへったくれも無いですね。 PWA導入「ホームボタンへ追加」について <script> // PWA window.addEventListener("load", () => { if ("serviceWorker" in navigator) { navigator.serviceWorker .register("/sw.js") .then(registration => { console.log("ServiceWorker registered"); registration.onupdatefound = function() { console.log("Exist update"); registration.update(); }; }) .catch(error => { console.warn("ServiceWorker error", error); }); } }); </script> そのページがロード完了したらserviceWorkerを起動させてregisterでインストール処理を走らせます。クリックされればthenが走ります。 また、このページにアクセスするたびに、registration.onupdatefound でキャッシュのアップデートがないか確認します。ある場合(つまりjavascriptが変更されている場合やcssが変更されている場合)はregistration.update();で更新処理が動作します。これでキャッシュの中身を入れ替えてバージョンを管理しています。 ここに表示されているのが、manifest.jsonの内容ですね。 headで読み込みするのを忘れずに scriptとmanifest.json読み込みできなければ上の図のようなボタンは発生しません。 ご注意を! 最後に 改めて読み返し見ると、わかりにくい箇所が何点かありますね・・・ これは今後記事の更新をしていくとしましょう! この記事が参考に慣れば幸いです。

自分のサイトをサクッとPWA化!PWA解説編①

2019/05/31 2019/05/31

PWAとは? 皆さんPWAご存知でしょうか?去年くらいから流行りだしたあの技術をですね! PWA(Progressive Web Apps)とは技術やライブラリではなくただのWEBサイトです。 Googleが定める要素を備えたWebサイトをPWAと呼びます。私個人の感覚ではありますが、この辺を勘違いしている人が多いと思います。 プログレッシブ ウェブアプリ: オフライン  |  Google Developers プログレッシブ ウェブアプリ: オフライン  |  Google Developersを見る PWAで何ができるの? これ気になるなる人多いと思います。 簡単に言ってしまうと、ネイティブ環境(OSのカードリーダー機能の読み込みなど)デバイスにアクセスする機能以外ならネイティブアプリと遜色ありません。 javascriptには位置情報を取得する機能や、カメラにアクセスする機能、カードリーダーのライブラリまで揃っています。セキュリティ的にはともかく、そういったライブラリ群など使用すればネイティブアプリには近づけるといって遜色無いでしょう。 代表例はこちら プッシュ通知機能 位置情報取得機能 オフライン機能 SPAによるネイティブライクな画面実装 ゲーム用javascriptライブラリを使用したゲーム実装 などなど。 これらを踏まえて、特徴とメリット、デメリットを見ていきましょう。 特徴 スマートフォン上でモバイルアプリのような振る舞いを見せる Service Worker機能(今度別記事で解説するとしましょう)の一つ「サイトのキャッシュ化」でオフラインでも使用することができる。 キャッシュ化されるの、表示が高速。 WEBプッシュ通知機能をService Workerなどが吸収してくれる。 メリット Google PlayやApp Storeの認証を待つ必要がない。 キャッシュの利用により、WEBアプリでは困難とされてきたオフライン対応が簡単。 WEBの技術で可能なため、ネイティブアプリを作成するための勉強コストが0。 デメリット Google PlayやApp Storeの強力なランキング機能や、あなたにおすすめ機能を使用できないため、新規ユーザーを獲得することが比較的困難。 現在、iOSでは機能制限されているため、普及しているとは言い難い。 使ってみた所感 PWAハマりますねこれは。上の画像については別記事で触れるとしましょう。 Monaca - すべての人にアプリ開発を Monacaは最新のWeb技術を活用したアプリ開発ソリューション。クロスプラットフォーム開発の効率化、組織の開発プロセスの標準化を実現します。 Monacaはご存知でしょうか。 3年位前に私も使用してアプリをリリースしたことがあるんですが、これに似た感じですかね。 HTMLとjavascriptでネイティブアプリを作成できるだけでもすごかったのに、今ではそのように振る舞うことができるわけです。 特性上、フロント言語によるSPAやSSRとも相性が非常によく、これからの主流になっていくのではないでしょうか。 また、審査をクリアする必要がないので、早急なアップデートが可能だったり、時間を無駄にしなくて済むなど他にもメリットがたくさんあります。 以外に知らない人が多い印象 知人にこの話をすると割と「なにそれ?」と帰ってきます。一般人以外にもエンジニアに聞いても3分の2くらいはこの反応。フロントエンジニアの知人に聞いてようやく90%くらいの反応でした。 Google PlayやApp Storeが強すぎて「アプリ=OSのStoreからダウンロード」という印象になっていますね。 ゲームを探すときも、まずそこを開くイメージです。 対して、ソシャゲであるグランブルーファンタジーはWEB上で動作するゲームです。 これはPWA移行夢じゃないハズですね。こういったWEB上で動作しているゲームには美味しい話ではないでしょうか。 だんだん実用的になってきている Firebase FireStore(NoSQL化とも言い換えられます) FCM(Firebase Cloud Messaging) フロント言語の普及 Angular React Vue 以上の技術が発展してきて、実用化に移っている起業も多数存在します 例えば?? Qiita エンジニアで見たこと無いって人はいるのでしょうか?組み込み言語の記事は少ないですが、緑色のあの画面を見たことがあるって人は多いではないでしょうか。 こもPWAですね。 日経新聞社 正直かなり驚きました。新聞社などはこういう技術に疎いものだとおもっていたので、ネットの電子版記事を読もうとしたとき、「ホーム画面に追加」ボタンが出てきたときは感動しましたね。 Twitter Lite Twitterはアプリが有名過ぎてPWA側のアプリを知らない人は多いのでは無いでしょうか? けど個人アプリ以外に活躍の場少なくない? そういう風に考えることも昔はありました。  大きい規模のWEBサービスだったりすると、オフライン化の対応だけでデスマになりそうです。 しかし最近その考えは無くなってきました。 オフライン対応はアプリチームがやっているようなものですし、大きい規模のWEBサービスでもドメイン管理をしていれば、PWAはすぐに可能です。PWAに規模は関係ありませんしね。SPAやSSRが必須というわけでもないので、普通にページ遷移してやればいいです。 オフライン対応も必須ではないので、できるところからコツコツとすることができます。 つまり、大きさや規模など考えなくても「導入するだけ」ならすぐにできます。 この敷居の低さが最大のメリットでもいいましょうか。 もちろんSPAやSSRを利用して、最大限のPWAのメリットを引き出すことができれば、ユーザーの皆様のためになるでしょう。 でもその一歩として、「とりあえず入れちゃう」のも悪くはないかもしれませんね。

【個人開発】勉強方法と開発手法、そのスピード感について【勉強方法】

2019/01/03 2019/05/24

【個人開発】勉強方法と開発手法、そのスピード感について【勉強方法】 今年の年始に今年の抱負メーカーというアプリを開発しました。(宣伝) 【個人開発】新年早々、今年の抱負をつぶやくWEBアプリをつくってみた(記事) 実は主だった周知はしていませんが、他にもたくさんのアプリを開発しています。 同じようにこの業界にサラリーマンとして働き始め、独学を中心に曲がりながらやってこれました。 この中で、自分でうまくいったと思う開発手法・勉強方法とそのスピード感について(今回は特にこちら)記事にしたいと思います。 特に技術に関係していませんが、開発に関係すると思うので、大目に見てやってください。 では、綴っていきたいと思います。 また、この記事は完全に僕の主観です。 異論は当然認めます。 兵は拙速を尊ぶ 何事も早い(速い)ほうが良い。 ことわざにも早さを重視するものが多いことから、歴史的に見ても開発開始は早ければ早いほど良く、開発期間は短ければ短いほど良いと思います。 これはイメージが着きやすいですよね。リリースが早くなればユーザーの満足度も高くなりますし、不具合対応も早ければ早いほど鎮火がスムーズです。 その中でも特に勉強はスピードを重視せよ スピード>正確性。これは僕の持論です。 昔のインターネット黎明期ならまだしも、現代のプログラミング界隈は 情報が多く 移り変わりが早く 透明度が高い(公開しやすく、指摘されやすい) です。 去年正しかったものが今年間違っていることはよくあることですね。 その中、僕が陥ったのは 情報が多すぎて正解がわからない 頑張って正解を調べた結果、いつの間にか古くなってる 結果、それは違う(古い)と指摘される 結果、モチベ低下する。 この解決策を考えた結果、考えるのをやめました ひたすら目の前のしたいこと、作りたい自作アプリの開発をしまくりました。 すると気持ちのいいくらいに知識が入ってきます。 なんでだろう?これにいくつかの答えを出しました。 失敗するまでが早い これは一番最初に思いつきました。 知らないことを検索するより、やってみてハマったところを少し勉強して実装する。 少し勉強しての少しがキモです。ここでガッツリ勉強するとハマった(完成しない)ままです。なぜそうなるかというと情報が多すぎて、情報の取捨選択をしているうちに刻々と時間が過ぎていくからです。ぶっちゃけなんとなくでいいとすら思っています。結果100%とは言えないまでも、60%くらいの知識がそこで付きますね。 単位あたりの勉強量が多くなる 勉強量/時間が当然増えます。 だって たくさん書いて たくさん失敗して たくさんやり直して いますから。 成果が出るのが早い これは感じている人が多いのではないでしょうか。成果が出ないと面白くないです。 早いほど成果が出て、楽しいですよ。 スピードは歳とってからはつかない スピードがないまま年をとると鈍くなってしまいます。ディスってるわけではありません。PC使えない世代、スマホ使えない世代のように新しい技術を噛み砕く力がなくなってしまいます。 逆に昔からスピード重視の方は、70歳プログラマーなど噛み砕くのが速いです。 この訓練だと思いましょう。 つまりここで何が言いたいかというと、 とにかく これであってるの?間違ってないの?指摘怖い・・・ 最初からコードを美しく、完璧なものにしたい。 この考えを捨て、今すぐ勉強ないしはコーディングを始めてください。 リファクタリングという考えもあります。 完璧でないコードを書いてしまったら「リファクタリングの勉強できるじゃん」とポジティブにとらえてください。 早く始めないと勉強している間に歳をとってしまいます。 「正確性を軽視せよ。」という意味ではない ユーザーがいないアプリならまだしも、いるアプリでバグがあれば当然直しますし、そもそもバグを出すな。これは僕もそう思います。 僕が言いたいのは最初から正確性を追究するなということです。 皆さんアジャイル好きじゃないですか。勉強方法もアジャイルにしましょう。(もしかしてアジャイルももう古いですかね?) それ・・・ユーザーに関係ある? 次は開発の方のお話をしたいです。 実はこれ実話でありました。 リリースが迫っているのに明らかに間に合わない修正をしたいという話でした。 処理としてのバグはありませんが、ソース上では確かに読みにくいものでした。 説得してマイナーバージョンで対応しましたが、完璧を求める過ぎるあまり自分しか見えていないエンジニア結構いると思います。(ちょっと偉そうですかね?) これは僕も陥ったことがありまして、あるレガシーコードを修正していたのですが、あまりにレガシーなのでイライラしていたんだと思います。 このときこう言いました。 >早く修正させてください!リスク(時間的な)を冒してでも対応するべきです! デザインや処理系は確かに古いですが、問題なく使えてるシステムでした。 >それ、ユーザーに関係ある?修正するのは良いけど、リスクは取らないよ。 今考えるとまさに自分のことしか考えていませんでしたね。 完璧を求めすぎて、周りが見えなくなるというのはこういうこと。 逆バージョンも見たことがあります。 >ユーザーに頼まれてこの処理をこう変えたいんだけど・・・ といわれ、 >え、この処理をこう変えるとコードが汚くなるのでやりたくないです。 コードの美しさ 処理系の完璧さ 使用言語 いろいろなこだわりがありますがユーザーがいる以上、できるだけ捨てられるようにしたほうが良いと思います。 ユーザー=神様ではない でも、ユーザー>コードですよね。 まとめ 自分のエンジンの最高回転数を上げるために、多少荒くていいのでスピード重視で勉強する。 ユーザーを相手にするときは、ユーザーを労って運転してあげる。 コーディングなんて割と適当で良いと思っています。 大事なのは最後までコードのお世話をすることです。 ちょっと挑戦的な記事でしたでしょうか? 去年いろいろあって、思うところがあり記事にしてみました。 また加筆修正すると思いますので、そのときはよしなに。

【個人開発】新年早々、今年の抱負をつぶやくWEBアプリをつくってみた

2019/01/01 2019/05/17

【個人開発】新年早々、今年の抱負をつぶやくWEBアプリをつくってみた 明けましておめでとうございます。 本年もよろしくお願いいたします。 早速ですが、新年早々アプリを作成しました。 今年の抱負メーカー アイデアを思いついて形にするまでに3日間という短い期間で作成したので、それまでの過程を記事にしようと思います。 アプリの内容 使い方は非常に簡単で、名前と今年の抱負を入力するだけで半紙に筆で書いた抱負画像を生成することができます。 下の方にある「つぶやく」ボタンをクリックしてツイッターにアップロードするという流れです。 他にはシェアした抱負が見られたランキング、PVランキングを搭載したぐらいですね(よくあるパターンです) こんな感じ アプリ作成の流れ 開発期間は3日間なので特に目立ったことはしていません。 アイデアを形にするまでにダッシュもダッシュ、猛ダッシュで作成しました。 https://ambition.nozomi.bike この子のドメインも既に買ってあるやつから適当に追加しました。 では、開発の流れにいきます。 1日目 アイデアを思いつき、それを形に使用と決意。 それと同時に競合してそうなサービスがあるかなどを調査。これは同じようなサービスを作成されている先人がいる場合、できるだけ作りを参考にしたり、自分の個性を表現する機会を得るためです。 個人的には学ぶは真似ぶ、同じような物があれば積極的に参考にしていきます。 今回は10分位調べて結果なさそうだったので、完全オリジナルです。 ついでにこのあたりから頭の中で設計開始。「2画面くらいやな〜」と思いながら構想を練ってました。 2日目 コーディング開始 ちなみに使用技術は Laravel Vue.js この2つです。目立った技術は使用していません。 敷いてあげるのであれば、画像生成のところを苦労しました。 Laravelで画像生成処理が搭載されているものと踏んでいたのでサクサク進むかなぁと思っていたのですが、見つけられずに自作しました。(もしこういう便利機能あるよって知っている方おりましたらご教示いただきたい。) 画像生成 大体こんな感じ /** * 抱負画像を作成します。 * * @param string $ambition 抱負 * @return string $toImage 保存先 */ private function createAmbitionImage(string $ambition) { // 元になる画像を取得 $image = imagecreatefromjpeg('./dist/001.jpg'); // ファイル名 $fileName = str_random(32).'.jpg'; // 保存先 $toImage = Ambitions::AMBITION_FILE_PATH.$fileName; // 設定情報 $size = 150; $x = imagesx($image) / 2 - 75; $y = 80; $color = imagecolorallocate($image, 0, 0, 0); $font = "../public/font/fude.ttf"; $verticalString = $this->convertStringToVirtival($ambition); if (count($verticalString) > 1) { $x = imagesx($image) / count($verticalString) * (count($verticalString) - 1) - 75; } // 画像と文字を合成 foreach ($verticalString as $string) { imagettftext($image, $size, 0, $x, $y, $color, $font, $string); $x -= 75 * 4; } imagejpeg($image, $toImage, 100); imagedestroy($image); $imagePath = asset(Ambitions::AMBITION_FILE_PATH. $fileName); return $imagePath; } /** * 文字列の文字と文字の間に改行コードを挿入し、縦書き対応にします。 * * @param string $string 対象文字列 * @return array $verticalString 変換後文字列 */ private function convertStringToVirtival(string $string) { $l = mb_strlen($string, 'UTF-8'); $chunked = array(); $col = 0; for ($i = 0; $i < $l; $i++) { if ($i % 7 == 0) { $col++; for ($j = 0; $j < $col; $j++) { $chunked[$col][] = ''; } } $chunked[$col][] = mb_substr($string, $i, 1, 'UTF-8'); } //配列を改行でjoin $verticalString = array(); foreach ($chunked as &$colValue) { $verticalString[] = join("\n", $colValue); } return $verticalString; } こう見るとマジックナンバー多いですね・・・課題に挙げられます。 image~系のメソッドを駆使して画像を生成しています。 正直このあたりは初めてのことでしたので、手探りでした。ここの機能開発に少し時間を取られたくらいでしょうか。 DB周り 他の機能に関してはただのDB通信なのでサクッと作成。 フロント この部分は今後のことを考えてVueで作成しました。 本当は全部Vueに任せるつもりだったんですが、時間がなくて慣れてる開発手法でやってしまったのが原因です。 フロントは只今勉強中・・・他のアプリは全てVueで作成しているのですが、この子は例外です。 SNS この部分はよくあるやつですね。 「SNS ボタン 設置」とかで検索すると出てきますよ。 つぶやく / 画像ダウンロード 機能として少し考え込んだのは左の「つぶやく」ボタン。 ぶっちゃけこれだけのアプリのためにOAuth認証を作るのも、使わせるのも面倒くさい じゃあもうシェアボタンで良いや。となりこの子の招待はシェアボタンです。 ボタンの作り方は <a href="https://twitter.com/intent/tweet?url=URL&text=表示したいテキスト&hashtags='ハッシュタグ1',ハッシュタグ2" onClick="window.open(encodeURI(decodeURI(this.href)), 'tweetwindow', 'width=650, height=1000, personalbar=0, toolbar=0, scrollbars=1, sizable=1'); return false;" rel="nofollow" class="btn btn-primary"> <i class="fab fa-twitter-square"></i>つぶやく </a> 画像ダウンロードは普通の画像ダウンロード処理です。 3日目 広告やCSSなどの最終調整とテスト 広告 最終的に使用していませんが、vue-google-adsenseというプラグイン便利でした。使用方法はリンク先に乗っていますので、見てください。 CSS ほとんどBootstrapに頼っているので目立ったところはありません。 こういうのを凝ってしまうと時間かかるので、有り物で作成してしまうくせがあります。 テスト 自動テストするまでもないので、テストコードは書いていません。手動テストです。 作ってみて 多分最速くらいに速いサービスです。 こんなに早く完成できたのは初めてです。 もっと言えばこんなに適当に作ったもの初めてです。 クセでマージンは3倍取るのが僕のポリシーなので、普段なら1人日の作業ですね笑。 競技プログラミングをしてるみたいでかなり面白かったです。 タイムアタックみたいな感じでした。 今年の抱負メーカー 意識したこと 季節感でアプリを作成してみました。 いろんなアプリが世の中にある中で埋もれてしまいやすいものがたくさんあると思います。 しかし日本人はイベントを重視する文化をもつので、季節やイベントに関するアプリは使用頻度は低いけど、廃れにくいのかなと思いました。 今回は年末は近いのと、自分で抱負をつぶやこうと思っていたのでこれを選びました。 スピード感 かなり焦りながら作りました。 なんてたって年末はすぐそこでしたから。 スピードを高めると技術獲得スピードが上がるというのは本当かもしれない。そう思えました。 これについては別記事にしようかなと思います。 記事にしました【個人開発】勉強方法と開発手法、そのスピード感について【勉強方法】 課題 3日間というのもあって機能不足が否めません。今後のアップデートにご期待ください。 SNSボタンの使用方法に意外な使い方があるような気がしてしようがありません。 画像生成部分に違和感を感じるので、再作成するかも。 参考 フォントフリー 和紙のフリー素材が無料 最後に 業務系というかビジネス関連でトドTaskというアプリも作成しました。 ただのタスク管理アプリなので、供給過多どころではありませんが、API利用(予定)やノート機能も搭載しているので、良かったら使ってみてください。API利用については近々ドキュメント公開します。 質問あれば回答できる範囲でするのでコメントお願いします