のんラボ

Reactを触ってみてVueとの違いをまとめてみた

2020/12/13 2020/12/13

Reactを触ってみてVueとの違いをまとめてみた こんにちは。Nonです。 私は、Laravelに付属しているという理由からVueを採用してフロントをいじってきた経緯があります。 Vueしか触ったことのない私が、フロントをしっかりと勉強する機会が最近増えてきました。 React勉強会なるものを社内で実施した結果、VueとReactの違いに気づいてきたので、そろそろまとめようと思い記事にしました。 とはいえ、何番煎じやねん。という感じなので、感想は他のサイトで上がっている内容と重複する部分もあるかもしれません。(できるだけ私個人の感覚も取り入れて記事にしたいと思います。) 参考記事はページ最下部に貼っておきます。 ということで、下記から「ある一点」に注目して比較してみます。 なので、一概にこっちが...というわけではありません。 それぞれの特徴を考慮してプロダクトを進めていくべきであり、〇〇さんが言ってたからこっちとか言うわけではありません。 採用する背景で重要なのは 経験者の有無、または今後のスキルセット ビジネスサイドを考えたアーキテクト など、包括的な開発背景の裏付けを基に採用を進めるべきというのが持論となります。(両方わかって両方触れる人がいれば完璧なんですが...w) 特徴 特徴については、他のサイトでもいっぱい語られていますね。 なので、私の価値観でサクッと済ませます。 Vue 技術の分離 Vueのテンプレート技術の採用はほぼ必須 HTML、CSS、jsの技術を明確に分けやすい。(Scoped CSSとか) UI / UX的。 画面の内容がメイン HTML / CSS がわかるだけでなんとかなる。(長所であり短所) 冗長ではないため、簡潔。 React 関心事の分離 Class / Entity / Component的。 各コンポーネントはClassでありEntity。 HTML(つまり各コンポーネント)をEntityクラスと受け止めるとすんなり開発が進む javascriptのパワーを最大限発揮できる。 jsxはjsの拡張(これがいいって感じる人は多いはず。) js(jsx)を中心にしているため冗長な分、設計がしっかりしている お手軽さ お手軽さという点に注目して比較してみます。後述する開発効率と重複してしまいそうですが、ここでは学習コスト、設計コストという面に注目します。(初速とも捉えることができます。) Vue > React Vueの特徴の一つに技術の分離があります。WEB / CSS さえ知っていればある程度のコンポーネントを作成できますので、学習コストはVueに軍配が上がるでしょう。 Reactはjsxに設計構想 / 方針についての深い理解を特に求められます。いい意味でも悪い意味でも作業者に高い期待を求めることになります。 フロントでガッツリとした処理を書かない 実装へのお手軽さを重視 フロント技術の網羅的な知識を持っていない人が参画し、作業者となっている こういう時はVueの方がお手軽です。 特にマークアップエンジニアやデザイナーが担当者の場合顕著です。 Vue WEB / CSS 部分を技術的に分離できるので、コーダー、デザイナーはこれまで通りの作業で作業を終えることができ、あとはjsをある程度知っている人にバトンタッチすることができます。 また、画面の動きを実装するという面でも、簡単なjavascriptの動作を勉強するだけで実装することができます。非同期処理や設計に関しては他のエンジニアに任せるという開発運用方法ですね。 例えば、styleやclass要素の変更を加えるときstringで十分扱えるので、特定の関数がフラグを判定しstringを返すというだけならjs入門したばかりの人でも十分しっかりと書けることでしょう。 React Reactのjsxにstyleやclass要素の変更を加えるときにはjsxの構文を知っている必要があります。 基本的にpropsは関数、オブジェクトで有るべきなのがReactです。マークアップエンジニアやデザイナーにはここが最初の障壁となるでしょう。 (もちろんプログラマ的にはClassと受け止めることができるのでメリットです。今は他の方を巻き込む時を想定しています。) (adsbygoogle = window.adsbygoogle || []).push({}); 更に詳しく 技術の分離が明確。HTML / CSS / jsの技術を明確に分けやすい。(特徴の一つ) 私の関わっているプロダクトは新機能追加の重要度が高く、開発スピードも求められます。フロントでの重大な処理もありません。今思うとVueを採用してよかったなと思います。 また、 コーディングができないが、UI / UXに特化したデザイナー javascriptをあまり知らないが、HTML / CSSを熟知しているコーダー がプロダクトに参画しています。 この時、デザイナーが作成した画面デザインをコーダーが再現することになるのですが、コンポーネント設計がされているフロントにコーダーが手を入れるとき、 javascriptにHTMLが実装されているReact templateとjavascriptを分離されているVue とではVueのほうが学習コストが低く、コーダーレベルでも手を出しやすいように感じました。 (もちろん、HTML / CSS / javascriptをきっちり分離しているプロダクトではこの対象ではありませんが、私のプロダクトは前述の通り実装スピードを重視しており、引き継ぎ時点でこのような設計はされていませんでした。) 特に。 Atomic Design by Brad Frost Learn how to create and maintain digital design systems, allowing your team to roll out higher quali... を採用しているとき、Reactはjavascript、jsxの知識をコーダーに求めることになりますが、Vueの場合はtemplateに書かれたpropertyに注意するだけでHTMLをそのまま書く感覚に近い気がします。 設計 設計という点に注目して比較してみます。 先に書いてしまうと、この章をうまく言語化できていません...申し訳ない。 Vue < React 少し具体例を上げるとするなら下記のような感じ。 私はPHPをよく使うので、Smartyをいじる機会も多いのですが、 Vue Vueは予め存在するテンプレートに対して処理を実行するイメージ 処理技術と描画技術を分けて書くため、Smarty(テンプレートエンジン)に処理を書きまくる感覚 Smartyに処理が書かれまくっているのとても嫌。 私が関わっているプロジェクトではそれを嫌って処理部分と描画部分を切り分けるような構造にしていますが、どうしても描画部分に引っ張られる部分がまだある。 React PHPでHTMLをどう描画するか記述しているイメージ 処理オブジェクトと描画オブジェクトを定義して関心事に分けて書くため、処理部分でHTMLを書きまくる感覚 上記から 設計を厳密にしたい 堅牢性を高めたい ビジネスロジックをフロントにバリバリ書く この辺を考慮するならReactを採用するべきでしょう。 更に詳しく フロントでバリバリ処理を実装する。(ここで言う処理とはデザインの動的変更や、アニメーションの実装ではなく、文字通りフロントでビジネスロジックを実装するパターンを指します。) jsxを採用しているReactは関心事の分離に特化している印象を受けます。 jsxについての説明は JSX の導入 – React ユーザインターフェース構築のための JavaScript ライブラリ マークアップとロジックを別々のファイルに書いて人為的に技術を分離するのではなく、React はマークアップとロジックを両方含む疎結合の「コンポーネント」という単位を用いて関心を分離します。後のセクションでコンポーネントについては改めて詳しく紹介しますが、現時点で JavaScript にマークアップを書くことが気にくわない場合、こちらの議論で考えが改まるかもしれません。 Vueはどちらかといえば技術の分離。お手軽さの章で述べたように、チームメンバーの技術の守備領域が明確になっている場合はこの恩恵を受けることができる。 対して、Reactは関心事の分離。プログラマはHTMLのことを熟知していなければなりませんが、ビジネスロジック処理と描画処理(あくまで処理であることが重要と思います。)を切り分けて考えることができるので、アーキテクトに恩恵を受けることでしょう。 これのどこかいいか、何が言いたいかと言うと、技術の分離ではないので全てをjs(jsx)でまとめる事ができます。 js(ts)のみでコンポーネントを設計したい jsコードの中でコンポーネント呼び出しを行い、htmlを変更したい などの実装がすべてjs(jsx)で完結するのがReact。とも感じています。 例えば、jsの中でコンポーネントを実装しようとするとき、 Vueの場合 export default { props: { label: { type: String, required: true, } }, data() { return { // データ定義 } }, template: '<button>{{ label }}</button>', // or render(createElement) {} } となるでしょう。ここのtemplateの部分がstringで書かれることになります。これがとても気持ち悪く感じます。 それなら<template></template>を採用しろ、という話になるのですが、その場合、jsのみで完結することができません(それマークアップじゃんと捉えられてしまいます)。 どうしても文字列を書く部分で出てきてしまい、設計がきれいという話にならなくなってします。 ではrenderではどうか? という話になりますが、jsxではないVueではcreateElementを利用して一つ一つDOMを作成しなければなりません。これが非常に面倒臭いです。プログラマチックといえばそのとおりですが、可読性が下がるのは間違い無いと思います。 Reactの場合 いつもの感じで書けばいいです。 import React from 'react'; class MyButton extend React.Component { construtor(props) { super(props); this.state = { // データ定義 } } // 関心事の分離的。 render() { const button = <button>{this.props.label}</button> return button; } // 技術の分離的。 render() { return ( <button>{this.props.label}</button> ); } } renderの部分でHTMLを書くのが基本となるので、設計上とてもわかり易い上に、jsxでHTMLを直接書く感覚にとても近いです。 何より、突然このコードを書いてもjsなら起動します。これがtsと相性のいい理由でもあります。フレームワーク間で結合のための設定を(比較的)しなくても済むのですから。 jsxについての説明は JSX の導入 – React ユーザインターフェース構築のための JavaScript ライブラリ このおかしなタグ構文は文字列でも HTML でもありません。 これは JSX と呼ばれる JavaScript の構文の拡張です。UI がどのような見た目かを記述するために、React とともに JSX を使用することを私たちはお勧めしています。JSX はテンプレート言語を連想させるでしょうが、JavaScript の機能を全て備えたものです。 とあるように、一つのObjectと捉えることができるもの大きな違いです。 (adsbygoogle = window.adsbygoogle || []).push({}); typescript(堅牢) 堅牢性に注目してみました。 Vue < React 堅牢性、特にtypescriptを採用する場合が顕著です。 このあたりはそれぞれのフレームワークにtypescriptを導入してみたらわかると思います。 導入については他の有用な記事にお任せしたいと思っていますが、Reactはtsとの相性が抜群です。 この時点でプログラマ視点からみた場合、堅牢さで軍配が上がるでしょう。 TypeScriptの導入障壁としてならVue ≒ React 結局は両フレームワークともに状態管理をメインに行うフレームワークなので、この部分さえ型厳密にしてしまえばいいのです。なので、導入障壁は同じ位と勝手に見てます。 しかし、導入後恩恵を受けやすいのはReactなので、このようにしました。 (adsbygoogle = window.adsbygoogle || []).push({}); 理由 render部分に注目するとVueはstringで、Reactはjsxで書かれていることにも注目できます。 tsで型厳密したときもReactの方がrenderへの恩恵を受けやすく、マークアップ部分が書かれたところも型厳密にしやすいことがわかります。(jsxはtsxとして型厳密にできますので。) 処理部分でも同じです。jsxはjavascriptの拡張なのでtsに置き換えやすく、関心事の分離が容易な上に型厳密までできるという堅牢さを持っています。 VueのtemplateはjsxではなくstringかcreateElementなので、この恩恵を受けづらいです。 Vueにjsxを導入する方法はありますが、それならReactを採用するでしょう。(そもそもそこまでしてVueの便利なテンプレート技術を捨てる理由がわからないです。私がそこまでするならReact移行を考えます。) また、Vueではpropsのバリデーションを実装できるのですが、typescriptの型厳密とVueのバリデーションでtsでNGでもVueでOKとなる場合があります。(設定のせいかもですが、この設定がそもそもめんどい) あと、Vueにts導入しようとすると、正味わけわからんくなる。 完全に独断と偏見だけどReact vs Vue してみた - Qiita 比較内容大まかに以下の点で比較検討をしました。私個人はVueよりもReactに慣れているので、偏った意見かもしれないけど参考になれば。ReactVue手軽さ△◎開発効率○○TypeS...... VueのTSサポートについて TSのサポートは微妙。Vueは手軽さとアバウトさが売りなのでしょうがないのかも。 確かに。 型付けがやりにくい(子Componentの場合いちいちデコレータを書かなくてはいけない) 型定義が間違っていてもコンパイルが通ってしまう(スキーマ !== 型定義 の場合でもとりあえずコンパイルは通ってしまう??) 上述した、Vueのprops問題。 子コンポーネントにpropsを渡す際に必須であれば required: true と定義するが、これは型定義で解決するべきことのはず。 そのとおりだ... 開発効率 開発効率という点に注目してみたいと思います。お手軽さと重複してしまいそうですが、ここではどちらかというと 実装時間 という観点に注目したいと思います。 Vue >= React 実装スピードは慣れという部分も大きいので、最終的には同様の効率になるかと思います。設計がしっかりできる分Reactのほうが効率いいように見えますが、そのために冗長な記述を大量に記載するのが特徴なので、結局トントンになるかもしれません。 Vue いい意味でアバウト 完全に独断と偏見だけどReact vs Vue してみた - Qiita 比較内容大まかに以下の点で比較検討をしました。私個人はVueよりもReactに慣れているので、偏った意見かもしれないけど参考になれば。ReactVue手軽さ△◎開発効率○○TypeS...... より引用 役割分担に非常に相性がいい 画面に必要な機能をVueテンプレートがたくさん用意してくれている React 堅牢なのはいいが、その分厄介(面倒)な部分もある。(〇〇したいだけなのに、ここまでしなきゃいけないの!?ってのは慣れてきた今でも感じることが多い) 役割分担がされておらず強力なフロントエンジニアがいる場合は個人のパワーに任せやすい。(↔エンジニアの力量に左右されやすいかも) 設計手法が明確にチーム内で共有されている場合はそこまで遅くならない(はず) 結局どっちを採用すればいいの? 冒頭にも書きましたが、 Vue デザイナーがフロントのメイン担当 役割分担がしっかりしていて、同時にその作業者である。 デザイナーもコーディングすることがあるとか コーダーがフロントではなくマークアップエンジニア的とか フロントにそこまで興味がない人が多い フロントでビジネスロジックを書くことが少ない 特定のページにのみ導入したい ちょっと試しにやってみたい。 部分的導入 速さを求めたい 学習コストをかけたくない このような場合はVueでしょう。 React プログラマがフロントのメイン担当 フロントエンジニアがたくさんいる 強烈なフロントエンジニアがいる 作業者がHTML / CSSに精通しているエンジニア 役割分担というよりチーム開発 デザイナーは画面デザインのみで作業者ではない コーダーのjsの理解が深い(エンジニアと呼べるレベル) 堅牢さを重視 重要なビジネスロジックが存在する 画面でもEntity的な考えを要求する フロントはこのようにあるべきという方針が存在する フロントとバックの明確な分離 デザインとフロントの明確な分離 このような場合はReactでしょう。 最後に ちょっと文章多めですみません。書き出したらこれもあるな。あっ、あれも。といった感じで追記していったので、まとまりが悪いかもしれません。 私はVueのほうが、Reactの方が...と言及するつもりはありません。 やはりチーム内、会社内で事情知るエンジニアに選択をせまり、答えを出した人に従うべきかと思っています。 結局、私の担当するプロダクトでは デザイナーが技術的背景を持たない HTML / CSSに特化したコーダーがいる 納期がすぐそこ といった、止むに止まれぬ事情があったのでVueを採用して書かれています。 しかし、弊社にもフロントを重視する考えが浸透してきて、フロントに対して前向きに取り組むような方が増えてきました。 この背景から中長期的にはReactの方がよかったかもと考えるようになってきて、少し違いをまとめてみようと記事にしました。 Reactへの移行も考えていますが、Vueが堅牢ではないとは明確に言えないので、Vueのts対応を進めて過去の頑張りをブラッシュアップする方針でもいいかもと思っています。(優柔不断) React勉強会については記事にできていませんが、PWA周りや、React Nativeについては今後も投稿していきたいと思います。 そのときはよしなに。 参考 完全に独断と偏見だけどReact vs Vue してみた - Qiita 比較内容大まかに以下の点で比較検討をしました。私個人はVueよりもReactに慣れているので、偏った意見かもしれないけど参考になれば。ReactVue手軽さ△◎開発効率○○TypeS...... 概ね私と同じ考え方でした。引用させていただいた部分も多いかも。 ありがとうございます。 あと、パフォーマンス面にも触れていていいと思った記事です。GraphQLについて言及しているものいいなと思いました。 ReactとVueのどちらを選ぶか - Qiita 主に非Web系のバックエンド開発者(C/C++, Java, Python等を使用)がReactとVueをそれぞれ簡単に触れて、感じたメリット、思ったことなどをまとめています。色々と書いてますが、どち... 私はこの記事に続いて、中長期的な戦略としてVue→React移行がしやすい設計をVueの段階でしておくことも重要だと考えています。

Z250で高山ダムへラーツー!

2020/12/06 2020/12/06

Z250で高山ダムへラーツー! こんにちは。のんです。 今回はまたまたバイクでツーリングへ行ったことを書こうと思います。 最高に良い一枚 時期は12月初旬頃です。 高山ダムへラーツー。ラーツーってなに? ラーツーって言うのは「ラーメンツーリング」のことですね。 ラーメンの材料と、材料を調理するコンロとかを持ってツーリングして、昼食などにラーメンを食べるツーリングのことです。 調理するって言っても大抵インスタントラーメンとかになるんですが、外で食べるラーメンはうまいから別にヨシ! 高山ダムへ到着するも火気厳禁らしい 高山ダムへ到着したけど火気厳禁だった...かなしい。 ちなみにちょうど放水時間でした。 この量確かに決壊したら下流の街は大変なことになりそう😅 ダムの近くの自然公園はすべて火気厳禁だったので、この川の下流でデイキャンすることになりました。 ちょうどいい感じのところを発見。地名は知らん。 ということで早速ラーメンを作って食べよう これが こうなる ただのインスタントラーメンなので、水を沸かしてスープとチャーシュー入れておしまい。 やっぱ外で食うご飯は美味しい。この日は意外と寒くなくて、ラーメン食べたらむしろ暑いくらいでした。 飯テロ この写真最高に良くないか??🤔 あと、椅子持って来たらよかったかも。 食後のコーヒーとプリン 川で遊びだす自分 ススキがいい味出してる。 最後に コロナ第3波+寒くなってきて走り納め感ある。 でも寒い中温かい思いをするのは何故かやめられないんだよなぁ... 呪術廻戦おもろいぞ ちょっとポーズ違くないか?🤔 最後に...バイクはいいぞ!! .

Z250で職場の仲間と美山かやぶきの里「雨」ツーリング!

2020/11/29 2020/12/03

職場の同僚と美山かやぶきの里「雨」ツーリング! こんにちは。Nonです。 今回は久しぶりにバイクでツーリングに行ったことを記事にしたいと思います。 何度目かの美山かやぶきの里へ行きました もう何回行ったかわからない美山かやぶきの里へツーリングしました。 ちょうど2時間くらいで行けるので、かる~くツーリングするには道も所要時間もお手頃な目的地なんですよね。 天気予報「曇りのち晴れ」だったよな...? この日は午前中天気が良くていいツーリングになると思っていました。 同僚が最近 レブル250 を購入して、せっかくなのでツーリング行こう!とも思い誘ってみたところ...って感じです。 レブルかっちょいいいいいいいいいい😆😆😆 ストファイ系が好きな私でも、これは欲しくなりました。座り心地も良さそう。250なので取り回しも楽だろうし乗ってて楽しいバイクかも。 で、肝心の天気ですが 案の定降られた。 なんで?かなり楽しみしていたのに、割と思いっきり振られました。 山の天気は変わりやすいとか言うけど変わりやすすぎやろ... バイクびっしょびしょ。 相方には悪いことをしました。 寒いし濡れるし、新車だし、で😇 でもなんだかんだ楽しかった かやぶきの里を観光はできなかった(滞在時間は昼飯食べただけ)けど、温かいそば美味しかったし、帰りは比較的天気安定してたしでまぁまぁ楽しかった。(もちろん晴天だったら最高だった) また行きたいですね。 最後に バイクはいいぞ! .

TDDでRSSを生成するライブラリを作成した話

2020/11/27 2020/11/27

TDDでRSSを生成するライブラリを作成した話 こんにちは。Nonです。 前回に引き続き、TDDでRSSを作成するライブラリについて話をしてみたいと思います。 完成したもの https://github.com/nonz250/simple-rss-maker-php https://packagist.org/packages/nonz250/simple-rss-maker-php 構造 RSS1.0に対応する余地を残しているので、SimpleRssMakerクラスの構造が少しおかしいかも。 ユースケース層も作ったけど、これいらなかったかなー。でもファイルを作成する処理をここに書きたかったので、まぁ良しとしましょう。 RSS1.0に対応していないですが、一応composerからはinstallできるようにしてる バージョンとしては1.0.0として作成しました。 https://packagist.org/packages/nonz250/simple-rss-maker-php しかし、RSS1.0にはまだ対応してないです。(RSS2.0の利用のほうが多いみたいだし別にいいよね😅) 構造的に悩んだところ ChannelをEntityにしたけどよく考えたらValueObejctなのかな?もっとシンプルな構造にすべきだったかも。DDDに固執しすぎた感ある。うーん。配列は作成したくなかったので、クラスにするのはあってるけどEntityとして定義するのは間違えた気がする。 SimpleXMLElementをつかってRSSを作成したのは、余計なstringとかで書かなくて済んだので良かったと思う。 RSS2エンティティの振る舞いだけで十分だったかなと思いました。 使い方 Packagistにも書いてありますが、 $simpleRssMaker = new SimpleRssMaker(); $xml = $simpleRssMaker // Channel settings. ->setChannel('title', 'link', 'description', 'language', 'copyright', 'category', 'pubDate') // Image settings. ->setImage('title', 'link', 'url') // Item settings. ->addItem('title', 'link', 'description', 'author', 'category', 'datetime') ->addItem('title', 'link') // Generate RSS2.0 string. ->rss2(); // If you have more than one article. $simpleRssMaker = $simpleRssMaker // Channel settings. ->setChannel('title', 'link', 'description', 'language', 'copyright', 'category', 'pubDate') // Image settings. ->setImage('title', 'link', 'url'); foreach($items as $item) { $simpleRssMaker = $simpleRssMaker ->addItem('title', 'link', 'description', 'author', 'category', 'datetime'); } // Generate RSS2.0 string. $xml = $simpleRssMaker->rss2(); こんな感じ。SimpleRssMakerだけで全部設定できるように作成しました。 最初の頃はChannelFactoryとか作ってChannelクラスをユーザーに使用してもらおうと思ってたけど、使いにくいかなと思ってやめました。 最後に フィード系のライブラリは他にも結構いいのがあったけど、総じてPHP5.3とかのライブラリだったので、差別化は出来てるかなと思っています。(PHP7.4以上が対象です。) RSS1.0に対応はしたいけどAtomは別にいいかな... ということで、しょぼいけどOSS作れてよかったと思いました。 そろそろ私も色々な人に貢献していきたいなとおもいますので、他のパッケージも作って行きたいと思います。 そのときはよしなに。 .

PHPでTDDをしながら簡単なRSS生成アプリを作ってみた

2020/11/13 2020/11/15

PHPでTDDをしながら簡単なRSS生成アプリを作ってみた こんにちは。Nonです。 今回は事情によりRSS用のXMLを作成するライブラリをTDDしながら作成したみた話をしたいと思います。 Github:https://github.com/nonz250/simple-rss-maker-php TDDについて 以前関連する記事をかいていました。これをより実践的にやってみようという話になりますね。 以前の記事はこちら。 テスト駆動はテストのための手法ではない【テスト駆動開発①】 TDDしながらコードを書いてみる TDDはRED→Green→Refactoringが基本ですので、まずはテストコードを失敗させるところからスタートですね。 <?php declare(strict_types=1); namespace Tests; use SimpleRssMaker\SimpleRssMaker; use PHPUnit\Framework\TestCase; class SimpleRssMakerTest extends TestCase { public function test__construct() { $simpleRssMaker = new SimpleRssMaker(); $this->assertInstanceOf(SimpleRssMaker::class, $simpleRssMaker); return $simpleRssMaker; } /** * @depends test__construct * @param SimpleRssMaker $simpleRssMaker */ public function testRss2(SimpleRssMaker $simpleRssMaker) { $rss2 = $simpleRssMaker->rss2(); $this->assertEquals("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", $rss2); } } <?php declare(strict_types=1); namespace SimpleRssMaker; class SimpleRssMaker implements SimpleRssMakerInterface { public function rss2(): string { return ""; } } 空文字を返す処理と理想的な<?xml version="1.0" encoding="UTF-8"?>\nを確認するテストを用意してテストを実行します。 .F 2 / 2 (100%) 結果はもちろん失敗です。 こちらを成功させるためにリファクタリングしましょう。 <?php declare(strict_types=1); namespace SimpleRssMaker; class SimpleRssMaker implements SimpleRssMakerInterface { public function rss2(): string { return "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n"; } } 空文字を返すのではなく、理想的な<?xml version="1.0" encoding="UTF-8"?>\nを返すようにリファクタリングしました。 .. 2 / 2 (100%) 結果はもちろん成功です。しかしこれでは、XMLタグを作成したとは言えないですね。思いっきりマジックナンバーになってしまっています。 <?php declare(strict_types=1); namespace SimpleRssMaker; class SimpleRssMaker implements SimpleRssMakerInterface { public function rss2(): string { $dom = new \DOMDocument('1.0', 'UTF-8'); $xml = $dom->saveXml(); return (string)$xml; } } XMLタグを動的に生成してくれるように変更しました。 .. 2 / 2 (100%) うまくいきましたね。 しかしこれではRSSを作成したとは言えないので、引き続きテストを修正します。 /** * @depends test__construct * @param SimpleRssMaker $simpleRssMaker */ public function testRss2(SimpleRssMaker $simpleRssMaker) { $rss2 = $simpleRssMaker->rss2(); $expected = <<<XML <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"/> XML; $this->assertEquals((string)$expected, (string)$rss2); } RSSに必要な<rss>タグを期待するテストへ変更しました。 ついでに、ヒアドキュメントを利用し、ファイル入力文字としてで期待するように変数を修正しました。 .F 2 / 2 (100%) 当然テスト失敗します。 次はこのテストをクリアするようにコードを修正しましょう。 <?php declare(strict_types=1); namespace SimpleRssMaker; class SimpleRssMaker implements SimpleRssMakerInterface { public function rss2(): string { $dom = new \DOMDocument('1.0', 'UTF-8'); $rss = $dom->createElement('rss'); $dom->appendChild($rss); $xml = $dom->saveXml(); $rss = new \SimpleXmlElement($xml); $rss->addAttribute('version', '2.0'); $xml = $rss->asXML(); return (string)$xml; } } PHPのDOMDocumentクラスとSimpleXmlElementを利用して、XMLタグとRSSタグを作成するコードを作成しました。 .. 2 / 2 (100%) テストもクリアしたので、問題なさそうです。 次は<rss>タグの中身がなければRSSとして機能しませんので、期待値を変更します。 /** * @depends test__construct * @param SimpleRssMaker $simpleRssMaker */ public function testRss2(SimpleRssMaker $simpleRssMaker) { $rss2 = $simpleRssMaker->rss2(); $expected = <<<XML <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <language>ja</language> </channel> </rss> XML; $this->assertEquals((string)$expected, (string)$rss2); } RSS2.0の必須項目である<channnel>タグを用意し、その中に<language>タグを期待するテストへ変更しました。 .F 2 / 2 (100%) テストはもちろん失敗です。 public function rss2(): string { $dom = new \DOMDocument('1.0', 'UTF-8'); $rss = $dom->createElement('rss'); $dom->appendChild($rss); $xml = $dom->saveXML(); $rss = new \SimpleXMLElement($xml); $rss->addAttribute('version', '2.0'); $channel = $rss->addChild('channel'); $channel->addChild('language', 'ja'); $dom = dom_import_simplexml($rss)->ownerDocument; $dom->formatOutput = true; $xml = $dom->saveXML(); return (string)$xml; } 必要タグとその値をXMLに追加する処理を追加し、テストします。 .. 2 / 2 (100%) クリアできたので、コードに問題はありませんね。 /** * @depends test__construct * @param SimpleRssMaker $simpleRssMaker */ public function testRss2(SimpleRssMaker $simpleRssMaker) { $rss2 = $simpleRssMaker->rss2(); $expectedDate = \DateTime::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:00', new \DateTimeZone('UTC')); $expected = <<<XML <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <title>タイトル</title> <link>https://example.com</link> <description>説明</description> <language>ja</language> <copyright>コピーライト</copyright> <pubDate>{$expectedDate->format(\DateTimeInterface::RFC822)}</pubDate> <category>カテゴリ</category> </channel> </rss> XML; $this->assertEquals((string)$expected, (string)$rss2); } では本格的にRSSの期待値を変更します。 .F 2 / 2 (100%) public function rss2(): string { $dom = new \DOMDocument('1.0', 'UTF-8'); $rss = $dom->createElement('rss'); $dom->appendChild($rss); $xml = $dom->saveXML(); $rss = new \SimpleXMLElement($xml); $rss->addAttribute('version', '2.0'); $channel = $rss->addChild('channel'); $channel->addChild('title', 'タイトル'); $channel->addChild('link', 'https://example.com'); $channel->addChild('description', '説明'); $channel->addChild('language', 'ja'); $channel->addChild('copyright', 'コピーライト'); $channel->addChild('pubDate', 'Wed, 01 Jan 20 00:00:00 +0000'); $channel->addChild('category', 'カテゴリ'); $dom = dom_import_simplexml($rss)->ownerDocument; $dom->formatOutput = true; $xml = $dom->saveXML(); return (string)$xml; } .. 2 / 2 (100%) かなり直列なコードですが、テストがクリアしたのでOKです。 しかしこれでは、動的に作成することができませんので、更に修正します。 <?php declare(strict_types=1); namespace Tests; use SimpleRssMaker\SimpleRssMaker; use PHPUnit\Framework\TestCase; class SimpleRssMakerTest extends TestCase { public function test__construct() { $simpleRssMaker = new SimpleRssMaker(); $this->assertInstanceOf(SimpleRssMaker::class, $simpleRssMaker); return $simpleRssMaker; } /** * @depends test__construct * @param SimpleRssMaker $simpleRssMaker */ public function testRss2(SimpleRssMaker $simpleRssMaker) { $rss2 = $simpleRssMaker->rss2(); $expectedDate = \DateTime::createFromFormat('Y-m-d H:i:s', '2020-01-01 00:00:00', new \DateTimeZone('UTC')); $expected = <<<XML <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <title>title</title> <link>https://example.com</link> <description>description</description> <language>ja</language> <copyright>copyright</copyright> <pubDate>Wed, 01 Jan 20 00:00:00 +0000</pubDate> <category>category</category> <image> <url>https://example.com/sample.png</url> <title>title</title> <link>https://example.com</link> </image> </channel> </rss> XML; $this->assertEquals((string)$expected, (string)$rss2); } } 期待値を微調整し、欲しいタグを少しだけ追加しました。 .F 2 / 2 (100%) テストは失敗しましたね、先程、動的に値を取得作成していきたいと言ったのでそろそろコードも本格的にしていきましょう。 <?php declare(strict_types=1); namespace SimpleRssMaker; use SimpleRssMaker\Rss2\Command\UseCases\CreateRss2; use SimpleRssMaker\Rss2\Command\UseCases\CreateRss2Input; use SimpleRssMaker\Rss2\Command\UseCases\CreateRss2Output; use SimpleRssMaker\Rss2\Models\Entities\Rss2; class SimpleRssMaker implements SimpleRssMakerInterface { public function rss2(): string { $input = new CreateRss2Input(); $output = new CreateRss2Output(); $useCase = new CreateRss2(); $useCase->process($input, $output); $rss2dom = $output->rss2(); return (string)$rss2dom; } } final class CreateRss2Input implements CreateRss2InputPort { } final class CreateRss2Output implements CreateRss2OutputPort { private Rss2 $rss2; public function output(Rss2 $rss2): void { $this->rss2 = $rss2; } public function rss2(): Rss2 { return $this->rss2; } } final class CreateRss2 implements CreateRss2Interface { public function process(CreateRss2InputPort $inputPort, CreateRss2OutputPort $outputPort): void { $outputPort->output(new Rss2()); } } <?php declare(strict_types=1); namespace SimpleRssMaker\Rss2\Models\Entities; use DOMDocument; use SimpleRssMaker\Shared\Models\ValueObjects\XmlEncoding; use SimpleRssMaker\Shared\Models\ValueObjects\XmlVersion; use SimpleXMLElement; final class Rss2 { public function createXMLDOM(): DOMDocument { $dom = new DOMDocument((string)$this->xmlVersion, (string)$this->xmlEncoding); $rss = $dom->createElement('rss'); $dom->appendChild($rss); return $dom; } public function createSimpleXmlElement(): SimpleXMLElement { $xml = $this->createXMLDOM()->saveXML(); $rss = new SimpleXMLElement($xml); $rss->addAttribute('version', '2.0'); $channel = $rss->addChild('channel'); $channel->addChild('title', 'title'); $channel->addChild('link', 'https://example.com'); $channel->addChild('description', 'description'); $channel->addChild('language', 'ja'); $channel->addChild('copyright', 'copyright'); $channel->addChild('pubDate', 'Wed, 01 Jan 20 00:00:00 +0000'); $channel->addChild('category', 'category'); $image = $channel->addChild('image'); $image->addChild('url', 'https://example.com/sample.png'); $image->addChild('title', 'title'); $image->addChild('link', 'https://example.com'); return $rss; } public function __toString(): string { $dom = dom_import_simplexml($this->createSimpleXmlElement())->ownerDocument; $dom->formatOutput = true; return $dom->saveXML(); } } とりあえずユースケースクラスとエンティティを作成し、その中で固定のXMLを返す処理にしてみました。 先程までSimpleRssMakerに書いていた処理をそのままエンティティに書き直しただけですね。 .. 2 / 2 (100%) テストはクリアしたので、構造に問題はなさそうです。 では次に値を動的に生成できるようにしていきましょう。 結構かっちり作成したいので、ValueObejctを作成します。 ValueObejctを作成するからにはこの子のテストを書かなければなりませんね。 最初と同様に期待するテストと失敗する処理を書いてからのスタートです。 <?php declare(strict_types=1); namespace Tests\Rss2\Models\ValueObjects; use SimpleRssMaker\Rss2\Models\ValueObjects\Link; use PHPUnit\Framework\TestCase; use Tests\TestHelper\StrTestHelper; class LinkTest extends TestCase { public function test__construct() { $expected = StrTestHelper::createRandomUrl(Link::MAX_LENGTH); $link = new Link($expected); $this->assertInstanceOf(Link::class, $link); $this->assertEquals($expected, (string)$link); return $link; } public function testFormatException() { $this->expectException(LinkFormatException::class); $expected = StrTestHelper::createRandomStr(); new Link($expected); } public function testLengthException() { $this->expectException(StrLengthException::class); $expected = StrTestHelper::createRandomUrl(Link::MAX_LENGTH + 1); new Link($expected); } } 期待するテストを書きました。 実装したコードはこちら。 <?php declare(strict_types=1); namespace SimpleRssMaker\Rss2\Models\ValueObjects; final class Link { private string $link; public function __construct(string $link) { $this->link = $link; } public function __toString(): string { return (string)$this->link; } } There were 2 failures: 1) Tests\Rss2\Models\ValueObjects\LinkTest::testFormatException Failed asserting that exception of type "SimpleRssMaker\Shared\Exceptions\LinkFormatException" is thrown. 2) Tests\Rss2\Models\ValueObjects\LinkTest::testLengthException Failed asserting that exception of type "SimpleRssMaker\Shared\Exceptions\StrLengthException" is thrown. クラスのインスタンス型のテストはクリアしていますが、バリデーション関連のテストで失敗していますね。 処理を書き直します。 <?php declare(strict_types=1); namespace SimpleRssMaker\Rss2\Models\ValueObjects; use SimpleRssMaker\Foundation\Helpers\Rules\UriRule; use SimpleRssMaker\Shared\Exceptions\LinkFormatException; use SimpleRssMaker\Shared\Exceptions\StrLengthException; final class Link { /** * Maximum character length of URLs when using IE */ public const MAX_LENGTH = 2083; private string $link; public function __construct(string $link) { if (!UriRule::isValidHttp($link)) { throw new LinkFormatException(sprintf('%s must start at https:// or http://', get_class())); } $this->link = $link; } public function __toString(): string { return (string)$this->link; } } httpかhttps://から始まるリンクでないと検証失敗するコードを追加しました。 There was 1 failure: 1) Tests\Rss2\Models\ValueObjects\LinkTest::testLengthException Failed asserting that exception of type "SimpleRssMaker\Shared\Exceptions\StrLengthException" is thrown. テストのエラーが一つ減ったのでうまく行ったようです。 <?php declare(strict_types=1); namespace SimpleRssMaker\Rss2\Models\ValueObjects; use SimpleRssMaker\Foundation\Helpers\Rules\UriRule; use SimpleRssMaker\Shared\Exceptions\LinkFormatException; use SimpleRssMaker\Shared\Exceptions\StrLengthException; final class Link { /** * Maximum character length of URLs when using IE */ public const MAX_LENGTH = 2083; private string $link; public function __construct(string $link) { if (!UriRule::isValidHttp($link)) { throw new LinkFormatException(sprintf('%s must start at https:// or http://', get_class())); } if (mb_strlen($link) > self::MAX_LENGTH) { throw new StrLengthException(sprintf('%s must be less than %s chars.', get_class(), self::MAX_LENGTH)); } $this->link = $link; } public function __toString(): string { return (string)$this->link; } } 続いて、最大文字長の検証コードを追加しました。 .. 2 / 2 (100%) これでLinkのValueObejctは感性しましたね。 public function test__construct() { $expected = StrTestHelper::createRandomUrl(Link::MAX_LENGTH); $link = new Link($expected); $this->assertInstanceOf(Link::class, $link); $this->assertEquals($expected, (string)$link); return $link; } このテストでValueObjectとしての機能をテストして、他のExceptionテストで検証のテストがクリアしています。 こんな感じでTDDは進めるといいかも TDDの強み このように、画面でデバッグを進めるのではなく、テストで開発を進めるのがTDDです。 テストは当然プログラムで動作しているので、プログラム上のエラーも拾ってくれるので、非常に進めやすいです。また、自分の期待する値をあらかじめテストに記載してやれば、正常に動作したときの動作確認もできて一石二鳥だということがわかるかと思います。 最終的にはこんな感じ 最終的なメインクラスのテストコードはこんな感じになりました。 (仕様的にはまだ満たしていなけどひとまず雰囲気だけでも感じてください) <?php declare(strict_types=1); namespace Tests; use DateTime; use DateTimeZone; use Exception; use SimpleRssMaker\Rss2\Models\Entities\Channel; use SimpleRssMaker\Shared\Exceptions\ChannelNotExistException; use SimpleRssMaker\SimpleRssMaker; use PHPUnit\Framework\TestCase; use SimpleRssMaker\SimpleRssMakerInterface; use Tests\TestHelper\StrTestHelper; class SimpleRssMakerTest extends TestCase { public function test__construct() { $simpleRSSMaker = new SimpleRssMaker(); $this->assertInstanceOf(SimpleRssMaker::class, $simpleRSSMaker); return $simpleRSSMaker; } /** * @depends test__construct * @param SimpleRssMakerInterface $simpleRSSMaker */ public function testException(SimpleRssMakerInterface $simpleRSSMaker) { $this->expectException(ChannelNotExistException::class); $simpleRSSMaker->rss2(); } /** * @depends test__construct * @param SimpleRssMakerInterface $simpleRSSMaker */ public function testChannelFactory(SimpleRssMakerInterface $simpleRSSMaker) { $channel = $simpleRSSMaker->channelFactory( StrTestHelper::createRandomStr(), StrTestHelper::createRandomUrl(), StrTestHelper::createRandomStr(), ); $this->assertInstanceOf(Channel::class, $channel); $simpleRSSMaker->setChannel($channel); $this->assertIsString($simpleRSSMaker->rss2()); } /** * @depends test__construct * @param SimpleRssMakerInterface $simpleRSSMaker * @throws Exception */ public function testRss2(SimpleRssMakerInterface $simpleRSSMaker) { $title = StrTestHelper::createRandomStr(); $link = StrTestHelper::createRandomUrl(); $description = StrTestHelper::createRandomStr(); $copyright = StrTestHelper::createRandomStr(); $pubDate = new DateTime('now', new DateTimeZone('UTC')); $category = StrTestHelper::createRandomStr(); $channel = $simpleRSSMaker ->channelFactory($title, $link, $description); $channel->setCopyright($copyright); $channel->setPubDate($pubDate); $channel->setCategory($category); $rss2 = $simpleRSSMaker ->setChannel($channel) ->rss2(); $expected = <<<XML <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0"> <channel> <title>{$title}</title> <link>{$link}</link> <description>{$description}</description> <language>ja</language> <copyright>{$copyright}</copyright> <pubDate>{$pubDate->format(DateTime::RFC822)}</pubDate> <category>{$category}</category> </channel> </rss> XML; $this->assertEquals((string)$expected, (string)$rss2); } } 最後に こちらがGithubのコードです。 https://github.com/nonz250/simple-rss-maker-php 機能的にはまだまだ途中なので、引き続き経過を記事にしたいと思います。 その時はよしなに。 .

AIを使っておすすめ商品を表示するスマレコ

2020/10/30 2020/10/30

AIを使っておすすめ商品を表示するスマレコ こんにちは。のんです。 今回はスマレジでスマレジ4のアプリコンテストが開かれましたでも言っていた、スマレコというアプリについて記事にしようと思います。 前から使ってみたかった AIが技術として普及し始めて結構経ちました。当時からAIを使って大きなデータを分析したいと思っていたので、スマレコ作成しました。 AIの作り方はそのうち別記事にしようかなと思います。 今回は紹介記事?的なものになるかと。 スマレジ4APIを利用した同期処理 元になるデータはスマレジ4APIを利用しています。しかしAIの処理には大量の元データがいるので、たくさんAPIをコールしなければなりません。(1000とかその程度の件数では無い。) この辺取引一覧で取得できるのかと思ったら、仕様上一覧で取得できるのはHeadの情報のみで、明細(商品情報など)は1件ずつ取得するしかないらしい。 ちょっとつらみですね。 Webhookで取引が登録されるたびにその情報を教えてもらって同期を取る手段も考えましたが、ちょっと訳あって保留中です。 ともかく、自前のDBにAPIで取得した情報をコピーしたあとで、分析を開始するという手段を取っています。(その方が速度的にも早い) スマレコの使い方 導線 スマレジでログインする 会員情報を同期する 分析ボタンを押す のみです。本当は分析終了時にメールで通知する処理を作成したかったのですが、スマレジ4のユーザー情報取得にメールアドレス取得はまだ実装していないので、この辺はスマレジのバージョンアップを待って、後日バージョンアップします。 課題 機能を持たない(例えばお会計の補助アプリとか、注文の補助アプリとか)ではなく、データをこねくるアプリなので、使い所が難しいです。店舗のデータ分析に熱心な方くらいで、普通の店長さんはこんなの考えないと思いますし。 相関値とか急に言われても、専門的な勉強をしてきた人しかわからない。見せ方に工夫しないとダメですね。ランキングのように変更して、多少の誤解は恐れず、一般化した方がいいかも知れません。 AIサーバーについては特に問題ないと思いますが、なにせ計算に時間がかかるので、同時に複数の処理を要求されたら流石に不安...ちょっと検証していかないとダメかも。 直近で抱えてる課題はこんなもんですかね? 安定稼働するまでは確実に持っていきたい。どれくらいの大きさのデータなら安定するかというのを探らなきゃいけないのも、こういうAI系アプリの面白いところかも。 予定 通知機能 これがなきゃ使おうと思わない 他の演算を利用した分析機能 AI演算処理の安定化、安全化 上記3点がクリアされれば、一段落といったところでしょうか。もちろん、現状の機能でも使用できるようにしていますが、より良くするための機能ですね。 最後に 今回はスマレコの紹介記事になりました。 本当は動画とかも用意したかったのですが、このブログまだ動画に対応していないので、その辺勉強してから出直してきます。 スマレジ4APIを利用したアプリは軽くてシンプルで業務の助けになるアプリがいいのかもと使ってみてわかりました。いろいろな会社のAPIを分析中心に使用してきた私の価値観が変わったかも。 次回はまだ何書くか決まってませんが、そろそろ技術的なアウトプットしたい。VueやDDDを習得してからというもの新しいインプットがないから焦ってます;; また記事にします。 その時はよしなに。 .

Pixel 5を買いました!

2020/10/17 2020/10/17

Pixel 5を買いました! こんにちは。Nonです。 久しぶりの記事になります。今回はPixel 5を購入したので、そのレビュー記事になります。 Pixel 5を購入する前はPixel 3aをユーザーだったので、その比較もできたらしていきたいです。 外観 筐体はガラス製から樹脂(?)製へ。 私、手汗を結構かくので、Pixel 3のときは手汗で指紋がついたり、少しベタついたりしていましたが、この筐体だとサラサラのまま使用できます。 大きさは男の手のひらでこのくらい。 Pixel 3aとほぼ変わらず、気持ち小さくなった感じもします。 (マットなブラックでかっこいい) ケース 【Spigen】 Google Pixel 5 ケース TPU 米軍MIL規格取得 耐衝撃 衝撃吸収 ラギッド・アーマー (マット・ブラック) ケースはこちらを購入。 Pixel 3を盛大に落として画面バキバキにした経験が忘れられなくて、本当はケースが大嫌いですが、購入してみました。 バイクにも利用するので一応、耐衝撃ケースです。 装着時はこちら。 表 裏 カメラの出っ張りが気になる人は気になるはず。私は気になる人でした。 しかしケースをつければちょうどいい感じでカメラも保護してくれます。 ただし、その分厚みも増しましたね。こちらは慣れでしょうか? 機能 Qi 機能面についてはただ一点!Qi充電機能しか目当てにしてませんでした!! こちらはAirPods Proです。 光ってるのがわかるように、スマホからの充電が可能になっています!地味に便利かも。(今後にも期待。) こちらはQi充電用のスタンドを購入しました。 スタンドはこちら。 Anker PowerWave 10 Stand(改善版), ワイヤレス充電器 Qi 認証 iPhone 11 / 11 Pro / 11 Pro Max/XS/XS Max/XR/X / 8 / 8 Plus Galaxy LG 対応 5W & 7.5W & 10W 出力 ブラック AirPods ProのQi充電機能に気づいてなかったので、スタンド型固定のものを購入しました。 こんなことだったら変形するタイプを購入すればよかった... くそぅ... バックキー 実は完全ベゼルレスのスマホを使うのは初めてで、バックキーを前提にこれまでスマホを利用していました。 しかしPixel 5はホームキーがiPhoneのようになっています。当然それに従ってバックキーもなくなってしまいました。 (バックキー魅力的だったのになー。せめて選択できればいいんだけど) バックキーが表示されるときもありますが、ある時とない時があるので、ないのも同義ですね。 こちらも少しずつ慣れていくしかありません。 5G 契約は4Gです!!w 5Gどこの契約しようかな。 その他 完全にAmazonのオススメに釣られましたが、ガラスカバーを画面用とカメラ用を購入しました。カバー嫌い派だったんですが、これはいいものですね。ガラス製のカバーとかあるの知りませんでした。 最後に 今回はPixel 5のレビュー記事でした。 5Gのパワーはまだ感じることはできませんが、Pixel 5のQi充電だけでもかなりいいものです!Google Homeの代わりにしたり、音楽プレイヤー的にしたり、色々使い道は多そう! あとはモバイル充電ですね。旅行先でThunderboltのコードはもう必要はないですね。 今回はこれまでにしておきましょう。 スマレコの進捗がありそうなので、次はその記事になりそうです。 その時はよしなに。 .

スマレジでスマレジ4のアプリコンテストが開かれました

2020/09/14 2020/09/14

スマレジでスマレジ4のアプリコンテストが開かれました こんにちはNonです。 今回は私の勤めているスマレジで開催されるスマレジ4のアプリコンテストについて記事にしようと思います。 アプリコンテストってなに? 今年の7月上旬頃にスマレジ4として、一般に公開されるAPIと、そのAPIを利用して作成したアプリのマーケットプラットフォームの提供を開始しました。 そのアプリマーケットを更に充実させるべく、社内でアプリとアプリの案の募集を始めたのです。 コンテストの賞金は、アプリをモノにして10万円〜100万円、アプリの案を提供して3万円〜10万円。もちろん内容の精査や順位付けをして適正なもののみに賞金が出ます。 参加条件は社内だけですので、一般の方は参加できませんが、この催し物で更にスマレジ4が賑わってくれえると嬉しいものです。 スマレジ4ってなに 大体はhttps://developers.smaregi.jp/を見ればわかりますが、要はAPIを提供しますよーってことです。しかもかなりの機能を公開している or する予定ですので、スマレジAPIを使用して自分だけのレジを作るなんてことも可能です。 データは2万店舗分なのでかなりのデータを提供することになります。無料でこれだけのデータを触れるのはすごいかも? で、私は何を作っているかというと... 個人開発ですので、大した機能のものは作れませんが、 会員の購入した商品からAIでオススメ商品を割り出す ということをしようと思います。 これだけの会員情報と取引情報があるので、前からAIの種にしたいな〜と思っていたのです。 名前はスマレジ・レコメンドから略してスマレコです。会員情報以外からもオススメの商品を割り出せるようにしていきたいのですが、リソースがない...今回は会員情報からのみですかね? デザインもBootstrapのままになってしまいそう。一応コンポーネント設計しっかりできているはずですので、デザインの拡張性もあるはず。 案はたくさんあるので、たくさん作ってみようと思う スマレジ4でやっと(社員の私でも感じるやっと感)APIの提供を開始することができて、できることの幅が広がりました。 これで社外の開発者だけでなく、社内の開発者もスマレジ4の実装を利用して自分の案を実現できるかもしれません。 ひとまずはアプリコンテストに注力することになるかな?と思います。 最後に 今回はスマレジ4とそのアプリコンテストについて記事にしてみました。 スマレジについて記事にすることが少なかった(技術的な記事の方が多い)ので、これまでとは変わった記事になっているかと思いますが、色々なAPIを利用して更に便利なサービスを作っていくのはいいことだと思ったので、記事にしました。 これを読んで、(スマレジ4)に限らず便利なアプリを作ってみようという気持ちのモチベーションに繋がれば幸いです。 この進捗についてはまた記事にしようと思います。 その時はよしなに。 .

私のお家の仕事環境(デスク編)

2020/08/26 2020/09/04

デスクをスッキリさせる系のnote記事読んでとても共感した話 こんにちは。Nonです。 今回はデスク周りをスッキリさせるために色々と工夫している方々の記事を見てとても共感した上に、私も真似にしてデスクスッキリ作戦をしている話をしようと思います。 もともとケーブル大嫌い 私はもともと工学系出身で、大学時代は自作PCとか、自作キットとか作るの大好きでした。(当時はまだDIYも流行ってなかったと思います。) 自作PCとか組み立てるとケーブルがとにかく多いんですよね。もうぐっちゃぐちゃです。 だいたいこのくらいか、それ以上のケーブルがマザーボードや電源から生えることになります。 これをなんとかしようと当時から色々していました。 また、私が大学に入学したくらいのときからスマートフォンとかが普及し初めてmicroUSBとかUSBケーブルを常備したり、普通に家庭で使用するレベルになったと思います。 だからケーブルがごちゃついて腹がたったのを覚えています。 社会人になってからはIT系の会社でネットワークを構築したりしていたので、LANケーブルと格闘したりしていました。 正味早く全部コードレスになればいいのに と思っています。 こういう考え方をするので、NFC技術はとても好きです。電子マネー決済はiDを主に使っています。 バーコード決済はなんか無理です。 リモートワークが本格的に始まった 幸か不幸かコロナの影響で、弊社にもリモートワークが普及し始めました。業種が業種でしたので、仕事の仕方がガラッと変わったわけでもなく、多少のリモート用設定さえすれば全てがうまくいく感じですすめることができました。 しかし、問題は違うところにありました。それは私の部屋が仕事に適していないということでした。いや、日常を過ごすだけなら十分な環境なんですが、仕事(8時間近く椅子に腰掛ける)環境としては微妙な感じでした。 もともとガジェット好きでしたので、必要なツールを以外と揃っているのですが、いかんせん「机」と「椅子」、そして「ケーブルの管理」がもう全然駄目でした。 まぁでもすぐにコロナも収束するだろうと思って特になんの対策も立てずにいたところ、デザイナーの方におすすめされた記事を読んで考えが変わり、お金はかかりますが、色々と揃えるようになりました。 そしてその記事がこちらです。 https://note.com/goando/m/me3ed2026f6ac noteをそんなに頻繁に利用するユーザーではないので、どういう仕組みかはわかりませんが、デスクをスッキリさせるジャンル?みたいなもので記事がまとまっているらしいです。 その記事の中でも特にこの辺が好き。 ケーブル1本だけの生産性最高なデスク環境をDIYなしで作った話 - 2019版 ケーブル嫌いのためのデスク周りをスッキリさせるテクニック 自分の部屋が「居住空間」ではなくなった 昇降デスクという存在は知っていましたが、居住空間には必要ないだろうと思っていました。 しかし、家で仕事をするので、居住空間ではなくなったのです。 まず最初に昇降デスクと少しいい椅子を買いました。 FlexiSpot パソコンデスク 電動式スタンディングデスク脚 昇降デスク 高さ調節 学習机 勉強机 ブラック(天板別売り) FLEXISPOT オフィスデスク用天板 DIY用天板 学習机 勉強机 スタンディングデスク120×60cmブラック SIHOO人間工学 オフィスデスクチェア メッシュ 通気性 昇降アームレスト 調節可能アームレスト ハイバックサポートクッション 腰サポート 360度回転 オフィスチェア まぁ生活変わりましたよね。最初はご飯食べたりゲームしたりする机だったので、生活感あふれる机上だったのですが、なにも置かなくなりました。(パソコンくらいかな?) 画像 買ったばかりの画像です。 この散らかっているケーブルをなんとかしようって感じですね。 というわけで、ケーブルを徹底的に排除してみた 最終的にこうなる なかなか排除できたんではないでしょうか?おしゃれなデスクを目指したわけではないので、無機質な感じになっています。私、こういう無機質というか無骨な感じ大好きです。 ケーブルがどこに行ったのかというと、「臭いものに蓋作戦」 です。 ケーブルの在り処 これだけ奥に隠れていたら、よほどのことがない限りケーブルを意識することがありません。 デスクにくっついているので昇降デスクを上下に動かしてもケーブルの長さの問題にぶち当たることは無いです。 昇降デスクの電源はこんな感じ。 うーん...手抜き! 私、両面テープで接着って嫌いなんですよね。ケーブル通す部品をデスクの裏にペタペタ貼りたくないので、こんな風になってしまいました。たまーに膝に当たるので今後の課題ですね。メーカーさんももう少し短くしてくれればよかったのに。 机の上に散らかるケーブルはどうしたの? 普段使用するPCはノートパソコン(Macbook Pro)なので、電源ケーブルやHDMIケーブルなどはどうしても机の上に出てきてしまいます。そこで、こんなものを取り付けました。 隠せないケーブルは整頓すればいいのです!! ゴム製じゃないプラスチックのスイッチ式のやつあればそっちでも良さそう。自動巻き取りとかしてくれないかなー? ちょっとした電源用に隠しコンセント デスクの電源を手の届かないところまで隠してしまったので、手近なところで一時的に電源が欲しくなるだろうなーと思ってデスクの支柱の裏に延長コードをペタリ。 この子は会社用のPCの電源など、頻繁に抜き差しする電源用に重宝しています。 正面からは全く見えません。 最後に noteに書かれている方は美しいデスクを目指している方が多い印象でした。例えばウッド調にしてシックな感じにしていたり、オーディオに特化させたりしたり。 私の求める美しさとは何も無いことなので、こんな感じになりました。 ちなみに昇降デスク、立ったり運動しながら仕事できるってだけじゃなくて、ちょっとした机の高さの調節がとても便利です。いろんな体勢でPCをいじれるようになったので、体がこることが少なくなりました。 次回は久々に記事の中にコードがあるものを書きたいですね。 その時はよしなに。 .

リモートワークが始まって大体半年が過ぎた感想

2020/08/26 2020/08/27

リモートワークが始まって大体半年が過ぎた感想 こんにちは。Nonです。 今回は3月くらいから始まったリモートワークについて少し話をしようと思います。 前々から働く場所に執着が無いタイプでしたので、リモートワークを一度くらいはしてみたいと思っていました。 幸か不幸かコロナの騒動の影響でリモートワークが本格的にスタートしました。 ちなみに、今回の騒動でリモートワークをするのは初めてです。 具体的にどういう働き方になったか? ぶっちゃけあまり変わってない! いや、変わってますよ?流石に。でも眼を見張るほど、「おぉ〜っ!」ってなるほど変わってないです。 リモートワークになる前からチャットツールは頻繁に使われていますし、口頭でのコミュニケーションよりも、チャットやドキュメントでのやり取りが多い職場ですので、リモートワークになってもあまり変わらない印象。 すこし変わったのは、内線電話が結構かかってきていたところが全てチャットになったというところでしょうか? 非常に助かりますね。 チャットツールに機能を求めるようになってきた G Suiteを採用しているので、Google chatを利用しているのですが、やっぱりSlackほど便利ではありません。(といっても私はSlack使い倒しているわけではないので、そこまで違いがわからないのですが) ただ、他のチームはSlack(無料版)などを利用しているところもあるようです。 ちなみに私は個人プレイが多いのでチャットをあまり利用しません。 通勤しなくていい!! いやぁ、これは本当に大きいですね。 私の趣味がツーリングなので、都会に住まいを構えていないのです。ツーリング行くときに便利な「駅から少し遠い」「高速沿い」の「少し安めで広いところ」を借りてますので、普段の通勤に大体60分くらいかけてました。往復で2時間ですね。 これがなくなったのは本当に大きいです。 ご飯をあまり食べなくなった 勤務地がオフィス街なので、職場の周りにはたくさんの飲食店が並んでいるのですが、私の住まいの周りにはそれが全然ありません。自炊かコンビニかなので、もう面倒臭くて昼ごはん抜いちゃうことがあります。これなんとかしたいんですよねー。 リモートになって良くなったこと みんなちゃんと考えてからアクションを起こすようになった これは私もそうなったと思います。 これまでは、わからないことがあれば、とりあえず直接聞いてみようみたいなところがありましたが、それが消えました。チャットのためにタイピングするのが面倒くさい、電話 / ビデオ通話するのが面倒臭いみたいなところができたからでしょうか? 自分の時間が増えた 通勤が無くなって、自分の時間が増えました。 なので、余った時間で勉強したり、自分のためのアプリ開発をしてます。 軽視されがちですが、これ会社としたら非常に大きいと思いますよ。通勤や残業の強制(という空気感)があると、やっぱり自分の時間をくれる会社とそうでない会社っていう印象を与えてしまいますから、いい人材ほど外にいってしまいます。 リモートになって悪くなったこと 無いと思います 強いてあげるなら、何か(技術的な / アイデア的な)閃きのトリガーが減った。くらいでしょうか?雑談はとても効果があるんだなと思いました。 今後も続けたいか?頻度は? 続けたいですね。少なくとも、プログラマーという職種の上ではメリットの方が明らかに多いです。 しかし、フルリモートは駄目だと思います。 やっぱり顔を合わせる時間は必要に思います。 その頻度は週1くらいでいいのではないでしょうか? その週1の出勤はコミュニケーション重視の勤務で、一週間に一回しか無いからこそ、大事なMTGになるのではないでしょうか? 最後に 今回は半年リモートワークをしてきたので、その感想を書いてみました。 中にはリモートワークできない業種もあるかもしれませんが、必要に応じて導入していきたいですよね。せっかく世界が便利になっているのに、便利になった(効率が良くなった)のだからもっと働け!ってのは少し違う気がします。 次の記事はリモートワークするにあたって自分のデスク周りを少し改造してみた話ができたらなと思います。 その時はよしなに。 .