11月 2018|sitateru tech blog

sitateru tech blog

シタテルの技術やエンジニアの取り組みを紹介するテックブログです。

2018年11月30日金曜日

AWSLambdaとServerlessを使ってみる[第2回]

こんにちは、シタテルエンジニアの工です!

AWSLambdaとServerless第2回に入っていきます!
前回は、AWSLambdaとserverlessについてさらっと確認して
serverlessでServiceをcreateするところまでをやってきました。
AWSLambdaとServerlessを使ってみる[第1回]|sitateru tech blog

今回は実際にSansan OpenAPIを利用して名刺情報を取得してみます 🚀

SansanAPI


公式ドキュメント Sansan Open API

名刺API 名刺Set取得(期間指定)を使ってみます。
SansanAPIを利用するにはAPI Keyが必要です。
取得方法はこちらを参考にしてください。

作る

前回createしたServiceを利用して作っていきます。
現在この2ファイルが作成されている状態です。

  • serverless.yml
    • 各種設定を書いていきます
  • handler.js
    • 処理を書いていきます

axiosインストール

今回は、httpリクエストにaxiosを使用します。

$ npm install axios

インストールされました

.
├── handler.js
├── node_modules
│  ├── axios
├── package-lock.json
└── serverless.yml

serverless.yml

環境変数の設定

lambdaには環境変数を設定することができます。
SansanAPIKeyを環境変数として設定してみます。
serverless.yml

# you can define service wide environment variables here
  environment:
    SANSAN_API_KEY: xxx

環境変数を利用する場合は、このように取得できます。

process.env.SANSAN_API_KEY

handler.js

それでは処理を書いていきます。
lambdaの非同期処理とcallbackについてはこちらを参考にしてください。

名刺情報はお見せできないので、取得した件数を出力してみます。

'use strict';

const axios = require('axios')
axios.defaults.headers.common['X-Sansan-Api-Key'] = process.env.SANSAN_API_KEY
axios.defaults.headers.get['Content-Type'] = 'application/json'

module.exports.hello = async (event, context, callback) => {
  var updatedFrom = "2018-11-26T01:00:00Z"
  var updatedTo = "2018-11-27T21:00:00Z"

  await axios.get(`https://api.sansan.com/v2.0/bizCards?updatedTo=${updatedTo}&range=all&entryStatus=completed`)
      .then(function (response) {
        callback(null, response.data.data.length)
      })
      .catch(function (error) {
        callback(error)
      });
};

deploy

cliでdeployします。
serverlessを使わない場合、serviceを手動でzipにしてawsにdeployする必要があるのでとても面倒です...

$ serverless deploy -v

deployが完了したら情報が出力されます。

...
Serverless: Stack update finished...
Service Information
service: hello-sansan
stage: dev
region: us-east-1
stack: hello-sansan-dev
api keys:
  None
endpoints:
  None
functions:
  hello: hello-sansan-dev-hello

lambdaの関数のところにも表示されています。

環境変数も設定されています。

実行

こちらもcliで実行します。

$ sls invoke -f hello
16

件数が取得できました。

おわりに

今回はlambdaからSansanOpenAPIを利用して名刺情報をゲットしてみました!
lambdaはサーバーのこと気にせずに処理だけ書けば良く、serverlessはcliでごにょごにょできるし、とても便利です!
sitateruではlambdaを使って、SansanとHubSpotの同期を自動化しています。
どこかのタイミング第3回としてserverless-offlineを使用したlambdaの開発についても書こうと思います。

, , , , , ,

2018年11月29日木曜日

Vueでwatchが動いてくれない

こんにちは、シタテルの藤本です。
主にSCS(Sitateru-Control-System)という生産管理システムのバックエンド(Rails)を担当しています。

SCSではRailsでのViewは基本hamlで書かれていますが現在Vueへと移行しようとしています。
最近私もVueを触る機会があり、watchを使用していてハマってしまったところを2点ほど書いておきます。

  1. Objectをwatchするときはdeepをつけよう
  2. = で追加してはリアクティブになりませんよ

1. Objectをwatchするときはdeepをつけよう

以下のようにdata(user_nameusers)がいて
その値が変更されたことを監視するようにしたい場合にwatchを以下のように書きます

  data () {
    return {
      user_name: '太郎',
      users: {}
    }
  }

  watch: {
    user_name: function (new_value, old_value) {
      alert(`user_name watch!!${this.user_name}`)
    },
    users: function (new_value, old_value) {
      alert(`users watch!!${this.users['name']}`)
    }
  }

  methods: {
    changeJiro () {
      this.user_name = '二郎'    
      this.$set(this.users, 'name', '二郎')    
    },
    changeSaburo () {
      this.user_name = '三郎'    
      this.$set(this.users, 'name', '三郎')
    }
  }

上記の状態でchangeJiro or changeSaburoを呼び出すと
user_nameしか監視されません。

Objectを監視したい場合には以下のようにwatchに対してdeepオプションを付与する必要があります。

    users: {
      handler: function (new_value, old_value) {
        alert(`users watch!!${this.users['name']}`)
      },
      deep: true
    }

公式の以下に記載があります。
watchについて

2. = で追加してはリアクティブになりませんよ

もう1点ハマったところでObjectの値をセットする際の処理の仕方です。

  1. とほとんど同じ内容ですがmethodsでのusersへのセットをuser_nameと同様に=に変更しています。

    data () {
     return {
       user_name: '太郎',
       users: {}
     }
    }
    
    watch: {
     user_name: function (new_value, old_value) {
       alert(`user_name watch!!${this.user_name}`)
     },
     users: {
       handler: function (new_value, old_value) {
         alert(`users watch!!${this.users['name']}`)
       },
       deep: true
     }
    }
    
    methods: {
     changeJiro () {
       alert(`check!! ${this.users['name']}`)
       this.user_name = '二郎'
       this.users['name'] = '二郎' //←ここが=でのセットに変わっている
     },
     changeSaburo () {
       alert(`check!! ${this.users['name']}`)
       this.user_name = '三郎'
       this.users['name'] = '三郎' //←ここが=でのセットに変わっている
     }
    }

こちらも同様にchangeJiro or changeSaburoを呼び出すと
user_nameしか監視されません。
ただしusers['name']を確認してみると値はセットされています。

原因としてはVue.jsはプロパティの追加または削除を検出できず、リアクティブになっていないため監視できないとのことです。
対応方法としてはわかっているもので2つあります。

  1. 最初から定義しておく
  2. setにて追加を行う

1. 最初から定義しておく

Objectのプロパティを最初から定義しておくことで監視することが出来るようになります。
dataに定義しているusersを以下のように修正します。

users: { name: '太郎' }

2. setにて追加を行う

こちらは1. に書いてある通りで、methodを以下のように修正します。

changeJiro () {
  this.user_name = '二郎'    
  this.$set(this.users, 'name', '二郎')    
},
changeSaburo () {
  this.user_name = '三郎'    
  this.$set(this.users, 'name', '三郎')
}

もっと詳細については以下をご参照ください。
リアクティブの探求

また配列に関しても同様の注意が必要で以下に詳しく書かれております。
配列の変化を検出

終わりに

1人でわりといい時間考え込んでましたが周りに聞いたら即解決しました。
悩みすぎるのはよくないと反省すると共に心強い味方がいることに大変感謝した次第です。
またVueの公式は大変日本語でも充実しているのでしっかり読もうと思いました。

以上です、これからVueをご利用される方の助けになれば幸いです。

, , ,

2018年11月28日水曜日

SPECデザインの舞台裏 [公開と非公開編 vol.1]

こんにちは、デザイナーの藤村です。
SPECという受注生産のためのサービス開発に今年の2月頃から関わっています。
→ SPECの説明はこちらで

SPECではサービスの一環として、受注販売用Webサイトを作成するためのCMSを提供しています。私は仕様検討と共にCMSの画面デザインをしています。今回は最近のなかで一番リテイクの多かった、サイトの公開/非公開機能のUIができるまでをご紹介します。

実装が決まるまで

当初SPECのCMSには「サイトを非公開にする」という機能がありませんでした。いずれ必要になるけれど、優先すべき開発が他にあるという判断で実装待ちになっていました。クライアントさんには、要望があればシタテルに直接ご連絡をいただくようお願いしていました。

が、そうは言っても間違えて公開してしまう、ということは十分に考えられます。開発チームでも議論を重ね、いよいよ実装することが決定しました。

▼当初のCMS画面

まだ公開していないサイト。公開ボタンがあります。

公開済みのサイト。ステータス表示として「公開中」はあるけれど、非公開にできるUIはない。

デザイン第一弾:とにかくシンプルに。

まずはこんな風に作りました。

画面の要素を最小限に、操作に迷わないように操作ポイントの要素もできるだけ少なく、という方針で作りました。「非公開」と書いてあるところをクリックすると選択肢が出てきます。どの状態に変更したいか選ぶと、ダイアログで本当に公開するのか聞いてきます。OKすると公開されます。ダイアログは「うっかり公開」を防ぐために付けました。

▼こんな感じ

ちなみにSPECチームでは、デザインを作ったらすぐにチームメンバーに見てもらいます。エンジニアもプロダクトオーナーもみんな見ます。気になった人がコメントを入れます。今回は画面遷移の変更というほどではなかったので、一気にデザインを起こしzeplinにアップしました。

表示と状態の微妙な関係

エンジニアから早速ツッコミが入りました。

「表示と状態にズレができる瞬間があるため、作りが複雑になり今のスケジュールでは工数が足りない。再考してほしい」。最初は理解ができず「??」となっていました。が、よくよく考えてわかりました。

①のときは、表示上は「非公開」になりますが、まだ本当にサイトが非公開になったわけではありません。保留の状態です。ダイアログで「非公開にする!」とした時点で、実際にサイトが非公開になるのです。つまり、①〜②〜ダイアログのあいだは、公開状態と表示にズレが出ているわけです。

表示とは = 画面に何と書いているか
状態とは = 実際にサイトが公開しているのか、非公開なのか

これがなぜ複雑なのか?
プログラム上、やらなければいけない制御が増えるから、です。

「非公開にしたい!」って言ったけど、やっぱりもうちょっと公開しておこうとなった場合、表示は「非公開」に戻っていなければいけません。「やっぱり非公開するのやめた」と言ったはずなのに表示が公開のままだったら、使っている人は混乱してしまいますね。使う人は気づかない部分ですが、こういう処理をきちんとしておくことはとても大事なことです。

実装の複雑さ、ユーザーへのケア、デザインするときに考えておくべきポイントはたくさんあります。フィードバックをもらったことで気づくことができました。ということで、チームメンバーのアドバイスをもとにデザインを修正しました。

デザイン第二弾:ボタンひとつで変わる世界

意外とサクッといきました。

▼こんな感じ

「変更」というボタンを追加しただけです。

第一弾のデザインが複雑だったのは、最初の画面で表示の切り替え「だけ」を行ったことが原因でした。であれば、表示と状態を「同時に」行えるUIにすればいいのです。最初の画面ではダイアログを呼び出すだけにし、ダイアログ上で操作するように変更しました。ダイアログでの操作ひとつで、状態と表示を同時に切り替えられるようになりました。ステップ数も、最大4つあったのが3つに減りました。万歳。

さあ、実装だ!、と思っていた矢先、仕様追加の依頼が入ってきました。。

(次回につづきます)

, , , ,

2018年11月27日火曜日

Gulpでラクに画像を圧縮!

こんにちは!
シタテル株式会社UI/UXデザイナーの堤です。

webサイトやメルマガで使う画像やバナーなどを作成する際に、サクッと手元で圧縮できる環境を用意しておくと便利だったのでご紹介します。
今回はgulpとパンダでお馴染みのTinyPNGやWebPに関するプラグインを使用して圧縮・生成します。

今回やりたかったこと

  • とにかく手軽に圧縮したい
  • 圧縮とともにWebPも一緒に生成したい

導入方法はNode.jsがインストールされている環境でプラグインをインストールします。

$ npm install gulp gulp-tinypng-compress gulp-webp

ディレクトリ構成

gulpfile.js
└images
 ├ src //圧縮元の画像ファイル置き場
 └ dist //圧縮後の画像ファイル置き場

gulpfile.js

const gulp     = require('gulp');
const tinyping = require('gulp-tinypng-compress');
const webp     = require('gulp-webp');

const paths = {
    srcDir : 'images/src',
    dstDir : 'images/dist'
}

gulp.task('webp', function () {
    gulp.src(paths.srcDir + "/**/*.{svg,gif,png,jpg,jpeg}")
        .pipe(webp())
        .pipe(gulp.dest(paths.dstDir));
});

gulp.task('tinypng', function () {
    gulp.src(paths.srcDir + "/**/*.{png,jpg,jpeg}")
        .pipe(tinyping({
            key: 'xxxxxxxxxx' // TinyPNGのAPI Key
        }))
        .pipe(gulp.dest(paths.dstDir));
});

gulp.task('default', ['tinypng', 'webp']);
  • TinyPNGのAPI Keyは、Tiny PNGもサイトから取得します
  • 無料で月500枚まで圧縮可能です

実行方法

$ gulp

// tinypngのみなら
$ gulp tinypng

// webpのみなら
$ gulp webp

WebPについて

Googleが開発している画像フォーマットです。
少し前まではWebKitを用いたウェブブラウザだけだったのですが、最新のEdgeや私が愛用するFirefoxはver65から対応するようで今後普及していきそうな気がしています。
https://caniuse.com/#search=webp

導入方法

まだ対応していないブラウザもあるため、cssで指定している背景画像の分岐はmodernizr.jsを使用して判別します。
modernizr.jsを参照すると対応ブラウザはclass="webp"、非対応ブラウザはclass="no-webp"というclassを自動的に付与してくれます。
あとはhtmlとcssを下記のように記載しておけばそれぞれ対応している画像を読み込んでくれます。

.webp .image {
    background-image: url("/images/background-hoge.webp");
}

.no-webp .image {
    background-image: url("/images/background-hoge.jpg");
}
<picture>
    <source srcset="/images/hoge.webp" type="image/webp">
    <img src="/images/hoge.jpg" alt="">
</picture>

まとめ

圧縮方法や使うプラグインはさまざまあり、外部サービスでも簡単に圧縮できるサービスはあるので、自分に合うものをいくつか試すのが良いかなと思っています。

最近LPで使用している画像を圧縮したのですがこれぐらい圧縮できました!

  • 元の画像 3.3MB ※そもそもがデカすぎやしないかいというのはありますが、、
  • TinyPNG 909KB
  • WebP 446KB

通信環境はどんどん良くなっているものの、初回の描画までに時間がかかると離脱に繋がるため、これからも面倒くさがらずに(もっと楽な圧縮方法を追求しつつ)圧縮していきたいと思います!

, , ,

2018年11月26日月曜日

Active Storage移行記:バリデーション編

こんにちはあさのです。

今回は、Ruby on Railsのファイルアップロード機能をPaperclipからActive Storageに移行したときの話を書こうと思います。

Paperclip

Paperclipはファイルアップロード用のGemです。

https://github.com/thoughtbot/paperclip

比較的導入が簡単であり、アプリケーションにファイルアップロード機能をつけるためによく使われています。

ですが、現在は "Deprecated" とされていて、Rails 5.2から標準機能の1つとなったActive Storageへの移行が推奨されています。

Active Storage

Active StorageはRailsのバージョン5.2から標準搭載されている機能の一つで、Paperclipと同様Active Recordのオブジェクトと紐づけたファイルアップロード機能を提供しています。

https://github.com/rails/rails/tree/master/activestorage

シタテルでもRails 5.2へのアップグレードが落ち着いたところでこの移行を行いました。

そんなわけで、移行にあたっていくつか注意点となったところを振り返っていきたいと思います。

今回はモデルのバリデーションの話です。

Active Storage でのバリデーション

Papaerclipにはバリデーション機能があります。

以下はiconという名前で扱う添付ファイルのバリデートをする例で、モデル内にこう書いておけば保存時に自動でチェックされます。

見てのとおりですが、ファイル形式は[jpg, jpeg, gif, png]のどれか、ファイルサイズが10MB以下である必要があります。

  validates_attachment :icon,
                       content_type: {
                         content_type: [
                           'image/jpg',
                           'image/jpeg',
                           'image/gif',
                           'image/png'
                         ]
                       },
                       size: {
                         less_than_or_equal_to: 10.megabytes,
                         message: I18n.t('errors.messages.file_too_large')
                       }

しかしActive Storageにはこのようなバリデーション機能はありません。

じゃあどうするんだ!という話ですが、素直にActive Recordのカスタムバリデーションを使いましょう。
これで同じようなことができます。

  validate :validate_icon

  def validate_icon
    return unless icon.attached?
    if icon.blob.byte_size > 10.megabytes
      icon.purge
      errors.add(:icon, I18n.t('errors.messages.file_too_large')
    elsif !image?
      icon.purge
      errors.add(:icon, I18n.t('errors.messages.file_type_not_image'))
    end
  end

  def image?
    %w[image/jpg image/jpeg image/gif image/png].include?(icon.blob.content_type)
  end

ちなみに、

  • attached? はファイルが存在するかどうか
  • blob.byte_size はファイルサイズ
  • blob.content_type はファイルタイプ

を取得しています。


ということでActive Storageのバリデーションについて書いてみました。

Paperclipからの移行はいろいろと作業があったので他のトピックについてもまた書いていきたいと思います。

それでは。

, , , ,

2018年11月24日土曜日

オンライン衣服生産システム[第4回] - マイオペレーター

縫製工場向けシステム - マイオペレーター

こんにちは!
シタテル株式会社CTOの和泉です。

シタテルのシステム紹介4回目。

第2回までにマイアトリエを使ってユーザーが衣服生産をリクエストし、SCSでコンシェルジ内容を管理することを紹介しました。

今回はついに、実際に衣服を作る縫製工場のための生産管理システム、マイオペレータについてご紹介します。

アイテムの生産管理

マイオペレーターはシタテルと取引をしていただいている縫製工場向けに無料で提供しています。一般的なウェブブラウザやスマートフォンで使えます。

下の図が、マイオペレータにログインした後のトップ画面です。

進行中の生産アイテムの一覧が表示されています。この一覧からそれぞれのアイテムの生産管理ページへと飛べます。
一件、アイテム生産ページを表示して内容を見てみましょう。

注目して欲しいのは左上のタブ、それとメッセージの表示画面です。マイアトリエやSCSと同じように、このマイオペレータでもアイテムの詳細な情報を閲覧しながら、コンシェルジュに簡単にメッセージを送信できます。
左上のタブは切り替えることで、アイテムの生産工程ごとの情報を表示されます。

この左上のタブの名前、見覚えがありませんか?
SCSでご紹介した"ボックス"について、皆さん覚えているでしょうか?

お気付きの通り、SCSのボックスとマイオペレータのタブは連動しています。

SCSで[概要〜見積もり]ボックスが作られれば、マイオペレータで[相談]タブが作成され、
SCSで[サンプル作成ボックス]が作られれば、マイオペレータでは[サンプル]タブが作成されます

このように連動して、SCSで入力された情報がマイオペレータで連携・表示されています。



スケジュールや発注仕様書、工賃など、衣服生産に必要な情報はこのタブを切り替えながら一通り確認できます。その他細かい部分はメッセージのやりとりで簡単にコンシェルジュに相談可能です。
随時この画面に情報が反映され、またサプライヤー側でも進捗を入力することで、アイテムの生産管理が行えます。

工場全体のスケジュール管理

1つずつのアイテムの生産管理画面に加えて、それらをまとめて管理するカレンダー機能も用意してあります。

カレンダーを使えば、全てのアイテムで予定されている期日についてカレンダー形式で表示して工場全体のスケジュールを見られます。

稼働状況通知機能

縫製工場には繁忙期と閑散期があります。突然依頼が入ってくることも珍しくありません。

画面から月ごとの稼働状況を選択すると、コンシェルジュにメッセージが送られます。直近の稼働状況を事前にここから連絡しておくだけで、シタテル側に繁閑を伝えることができます。簡単に受注相談を調整できます。

トーク

トーク機能ではアイテムを限定せずにスケジュールの調整やその他全体的な(雑な言い方をするなら”ざっくばらん”に、”どんなことでも”)やりとりを行うことが出来ます。システムの改善要求などをトークで教えてくださる工場もあり、とても助かっています。

まとめ

今回の記事でシタテルのシステム紹介は一旦終わりですが、シタテルではシステムの開発・改修を日々行なっています。

このシリーズ記事を書いている間にもSCSと外部ビジネスツールとの連携や工場向けのマイオペマガジンの実装がされました。これからも追加機能がどんどんリリースされます。

引き続き紹介していきますのでお楽しみに!

, ,

2018年11月22日木曜日

AWSLambdaとServerlessを使ってみる[第1回]

こんにちは、シタテルエンジニアの工です!
AWS Lambdaを触る機会がありましたので、ServerlessFrameworkと一緒にいじいじしてみました!
シリーズで、
Serverlessをインストール
AWSLambdaでSansanの名刺データを取得してみる
serverless-offlineでAWSLambdaをローカルで実行
なんかを書いていこうと思います!

さらっとAWSLamdaとServerlessFrameworkについて

AWS Lambdaとは


AWS Lambda とは - AWS Lambda

AWS Lambda はサーバーをプロビジョニングしたり管理しなくてもコードを実行できるコンピューティングサービスです。

つまり、流行りのサーバーレスてやつで、サーバーを準備しなくてよいので、ちょっとした処理の実行など大変助かります。
しかも、LambdaはNode.js (JavaScript)、Python、Java (Java 8 互換)、C# (.NET Core)、 Goに対応しています!
様々な言語に対応しているので学習コストもかからないのがいいですね。

シタテルでは、HubSpotとSansanのデータ同期や、SlackCommandでリリースPRを作るなどで使っています。

Serverlessとは


Serverless Framework

The Serverless Framework is an open-source CLI for building and deploying serverless applications.

つまり、サーバーレスアプリケーションの開発を手助けをしてくれるやつです!
AWS Lambda単体で開発してみるとわかるのですが、ローカルでの開発やビルド、デバッグやらが面倒です。
このServerless Frameworkを使えばそのあたりのもやもやを解消してくれます!

作ってみる

Serverless Framework - AWS Lambda Guide - Introduction こちらがAWS用のServerlessFramework公式ドキュメントです。 基本的にこちらの内容に沿って進めていきます、

今回は、Sansanの名刺データを取得してみます。

まずはServerlessFrameworkをインストール

$ npm install -g serverless
$ serverless -v
1.33.2

正しくバージョンが表示されていたら、インストール完了です!

Serviceを作る

Serviceはプロジェクトのようなもの。
今回は、nodejsで作っていきますので、aws-nodejsを指定。
その他の言語を使いたい方はこちらを参考に。

$ serverless create --template aws-nodejs --path hello-sansan

実行すると

Serverless: Generating boilerplate...
Serverless: Generating boilerplate in "/Users/mogura/work/sitateru/lambda/hello-sansan"
 _______                             __
|   _   .-----.----.--.--.-----.----|  .-----.-----.-----.
|   |___|  -__|   _|  |  |  -__|   _|  |  -__|__ --|__ --|
|____   |_____|__|  \___/|_____|__| |__|_____|_____|_____|
|   |   |             The Serverless Application Framework
|       |                           serverless.com, v1.33.2
 -------'

Serverless: Successfully generated boilerplate for template: "aws-nodejs"

このような構成で、Serviceができました!

hello-sansan
   ├── handler.js
   └── serverless.yml

次は、実際に処理を書いていきます。
が、長くなりそうなので今回はここまでに。

おわりに

今回は、ServerlessFrameworkでserviceを作るところまでをやってみました。
次回は、実際にAWSLamdaでSansanから名刺データを取得するとことまでをやっていきます! 🚀

, , ,

2018年11月21日水曜日

Visual Studio CodeでNuxt.jsにデバッガをかける

こんにちは!
シタテル株式会社CTOの和泉です。

シタテルではフロントエンドの開発にNuxt.jsを使っています。

デバッガをかけてたいときはどうしたらいいんだろうと思って調べていたら良さそうなやり方を見つけたので自分の記録がてら書いておきます。

参考:
https://codeburst.io/debugging-nuxt-js-with-visual-studio-code-724920140b8f

手順

Nuxt.jsのプロジェクトを作る部分は割愛します。

1. package.json に コマンド追加

"scripts": {
  "debug": "node --inspect node_modules/.bin/nuxt",

2. デバッガの設定

デバッガを開く
画像左下の虫マークをクリック

実行の設定
図中「Launch Program」右の歯車をクリックして実行設定を開く

実行の追加
右下「Add Configuration」をクリックして「Launch via NPM」を選択すると実行設定が追加されます。追加後はlaunch.jsonファイルを保存してください。

3. デバッガの実行

デバッガの実行
追加された「Launch via NPM」を選択して再生ボタンを押すとデバッガが実行されます。

デバッガの実行
ブレークポイントは debuggerと記述

デバッガの実行
ブレークしたところで変数などを確認できます。

以上、簡単ですがNuxt.jsにデバッガをかけられるようになりました。

, , , , , ,

2018年11月20日火曜日

独自マークアップ言語によるケアラベル(品質表示ネーム)エディター

こんにちは、シタテルの茨木です。

衣服には必ずケアラベル(品質表示ネーム)というものがついています。洗濯の方法などが書いてあるアレですね。

凝ったデザインにすることもありますが、大体はパターンが決まっています。
今回は、独自のマークアップ言語でケアラベルを作れるようにしてみた、という内容です。

完成イメージ

  • 中央の入力欄で独自マークアップを入力すると、左にケアラベルがリアルタイムプレビューされる
  • 画像としてケアラベルをダウンロードできる
  • 右欄でCSSによるデザイン微調整が可能(おまけ)

ソースコード

https://github.com/tibaraki/care-label

目次

  1. マークアップをパースして配列に
  2. 配列からDOMを描画
  3. CSSを適用

マークアップをパースして配列に

本件の肝です。

パーサコンビネータparsimmonを使用します。

パーサコンビネータは文法要素の組み合わせで言語(文書)構造を定義していきます。
たとえば正規表現も文書構造を定義するものですが、正規表現は再帰が表現できないという限界があります。
今回使うようなパーサは再帰を記述できるので、理論上あらゆるプログラミング言語の文法チェックが可能です。

今回はこれをつかって、独自マークアップ言語の文法を定義してみます。

下記は入力例&出力例&パーサの本体です。
parseにマークアップを投げるとパース後の配列を返してくれます。

@id1
  aaa
@id2
  ccc
  @id2-1
    ddd
    eee
    @id2-1-1
      xxx
    fff
  @id2-2
    ggg
    hhh
[
  [
    "@id1",
    [
      [
        "aaa"
      ]
    ]
  ],
  [
    "@id2",
    [
      [
        "ccc"
      ],
      [
        "@id2-1",
        [
          [
            "ddd"
          ],
          [
            "eee"
          ],
          [
            "@id2-1-1",
            [
              [
                "xxx"
              ]
            ]
          ],
          [
            "fff"
          ]
        ]
      ],
      [
        "@id2-2",
        [
          [
            "ggg"
          ],
          [
            "hhh"
          ]
        ]
      ]
    ]
  ]
]
import {regex, string, lazy, seq} from 'parsimmon'

function lexeme(p) { return p.skip(regex(/[ \n]*/)) }

const lparen = lexeme(string('{'))
const rparen = lexeme(string('}'))

const elem = lazy('', () => { return block.or(line) })

const id   = lexeme(regex(/@[\w-]*/i))
const atom = regex(/[^\{\}\n ]+/).skip(regex(/ */))

const line  = regex(/[\n ]*/).then(atom.many()).skip(regex(/\n+/))
const block = regex(/[\n ]*/).then(seq(id, lparen.then(elem.many()).skip(rparen)))

const root = block.many()

export default {
  preserve(string) {
    let value = ''
    let level = 0
    string.split(/\r\n|\r|\n/).forEach((line) => {
      const indent = Math.floor(line.match(/^ */)[0].length / 2)
      if (level < indent) {
        value += "{".repeat(indent - level) + "\n" + line + "\n"
      } else if (level > indent) {
        value += "}".repeat(level - indent) + "\n" + line + "\n"
      } else {
        value += line + "\n"
      }
      level = indent
    })
    value += "}".repeat(level)
    return value
  },
  parse(string) {
    return root.parse(this.preserve(string)).value
  }
}

文書構造の定義

jsの前半部、constの並ぶ箇所は文書構造の定義です。
意味としては下記のような感じです。
elemとblockが相互参照して再帰しているのがわかるかと思います。

const elem = lazy('', () => { return block.or(line) })

elemはblockまたはlineで構成される

const block = regex(/[\n ]*/).then(seq(id, lparen.then(elem.many()).skip(rparen)))

blockはidで始まり、lparen{とrparen}で囲まれた複数個のelemで構成される

preserve

preserveは前処理です。

文書構造の定義でしれっと{}でブロックを定義していましたが、今回作りたいマークアップはインデントでネストを表現する方式なので、前処理でインデントを{}に変換しています。

ここもパーサでできればカッコいいのですが、うまいやり方は思いつきませんでした。pythonとかどうしてるんですかね?

配列からDOMを描画

vueで書きます。パース後の配列(persed)とバインドしておけば、リアルタイムに再描画されて楽です。

    div#view(:style="viewsize" ref="view")
      div(v-for="elem in parsed")

        div(v-if="check(elem, /^@mixings/)" :class="classname(elem)")
          table
            tr(v-for="mixing in take(elem)")
              td(v-for="i in columns(take(elem))") {{ mixing[i-1] || "" }}

        div(v-else-if="check(elem, /^@marks/)" :class="classname(elem)")
          div(v-for="mark in take(elem)")
            img(v-if="isValidMarkId(mark[0])" :src="`/img/${mark[0]}.jpg`")

        div(v-else-if="check(elem, /^@/)" :class="classname(elem)")
          div(v-for="e in take(elem)") {{ e.join(' ') }}

基本的には@hogeをそのままcssのclass(.hoge)として適用し、cssでデザインを定義していく戦略なので、あまり複雑なことはやりません。

ただし、@marksは画像(洗濯マーク)に差し替える必要があるのと、@mixingsはtableでレイアウトしたかったので、vue内で特別扱いしてあげます。

CSSの適用

CSSも書き直したらリアルタイムに反映されてほしいので、更新時に動的に差し替えに行きます。

    applyStyle() {
      const old = document.getElementById('inserted-style')
      old && old.parentNode.removeChild(old)
      const obj = document.createElement('style')
      obj.setAttribute('id', 'inserted-style')
      obj.appendChild(document.createTextNode(this.style))
      document.getElementsByTagName('head')[0].appendChild(obj)
    },

あまりキレイじゃないですが、head要素に無理やり差し込みます。

その他

HTMLからの画像化は、下記ライブラリを使用しています。
https://github.com/tsayen/dom-to-image
どうもフォントまわりの挙動が怪しく、OS/ブラウザによっては画像出力が上手くいかない場合があります。

まとめ

一通り作ってから、yamlでも良かったのでは、とちょっと思ってしまいました。

とはいえ、非エンジニアにはyamlも辛いでしょうし、目的特化して打鍵の少ない文法を定義したい、というところに独自マークアップの需要はあるかもしれません。WYSIWYGに発展できたりするといいですね。

ご参考になれば幸いです。

, , , ,

2018年11月19日月曜日

スネーク?キャメル?ケバブ?命名規則のカオスが発生

こんにちは!
SCSチームのいしづかです。

シタテルでは主にRails + Vue.jsにてシステムを開発しています。

生産管理を行うシタテルコントロールシステム(SCS)もRailsで書かれており、Viewは基本的にhaml + scssです。

SCS全体のAPI + SPA化によるマイクロサービス化計画も進んでいる中、ここ最近作られている画面はhamlの中にVue.jsを埋め込むという方法が取られています。

その埋め込み方法は別の機会に書くとして、そこで出てきた 命名規則のアレコレ についてレポートしたいと思います。

Railsはパスカル + スネーク、Javascriptはキャメル、htmlはケバブ・・・

表題の通り、いろいろ混ざりました。

Railsでは、ネームスペースやクラス名はパスカルケース(ClassName)、それ以外のメソッド名などはスネークケース(method_name)で書きます。

定数などはアッパーケース(CONST_VALUE)で書きますね。いつの間にか3種類使い分けていました。

私自身、前職ではC#.NETでWindowsアプリケーションを作っていたのでパスカルケースを見ると安心します(笑)

Vueを使いだしてから、メソッド名はキャメルケース(methodName)、htmlやcssのidやクラスなどはケバブケース(class-name)が登場してきました。

・・・ついに1つのRailsプロジェクトに、ほぼすべての命名規則が揃ってしまったのです。

RailsとVueで分かれていればまだよかったかもしれませんが、Railsで書いたAPIのjsonがスネークケースで出力されてしまうため、Vue側にもスネークケースが進出してしまいました。

そこで、さすがにルールを設けようということになったのです。

統一ルール発令

Railsで使っているパスカルケース・スネークケースは崩すことができません。これはこのまま。

Vue側は データに関わるもの(data・computed)はスネークケース、処理に関わるもの(methods)はキャメルケース、html・css周りはケバブケース というルールに統一しました。

なんとなく複雑っぽいですが、メソッドとhtml周りはそのままで、データに関わるところだけちょっとRailsに寄せたという形です。

これでRails側はこれまでのソースを流用できますし、Vue側ではJsonをパースしてバインドする際、スネークケースが出てきてもOKです。

Vueが入ってきて発生した命名規則の混乱は、この統一ルール発令によってひとまずしばらくは沈静化するでしょう。。。

API + SPA化計画では、フロントはキャメル統一の予定

とはいえ!Javascriptは基本的にキャメルケース。
現在実装中のSCS APIでは、RailsからJsonを出力する際にキャメルケースに変換するように実装しています。

これでSPA側でデータを受け取る時だけスネークケースにしなくても済みそうです。

まとめ

これまでとは異なる言語やプラットフォームを使う時、既存のものとの整合性が取れなくなるときがありますね。

今回、私たちは「命名規則がカオスになる」という形でそれが表れました。

シタテルではそんなカオスとも仲良くしながら(闘いながら?)、日々新しいものにも取り組みつつシステムを構築しています。

, , , , ,

2018年11月17日土曜日

オンライン衣服生産システム[第3回] - マイアトリエ

ユーザー向けシステム - マイアトリエ

こんにちは!
シタテル株式会社CTOの和泉です。

シタテルのシステムを紹介する記事第3回。今回はユーザー向けのシステム「マイアトリエ」をご紹介します。

マイアトリエは服を作りたいと思うユーザーの皆さまがシタテルにご相談いただく窓口です。

  • 作りたいアイテムの相談
  • 進行中アイテムの状況確認

この2つを オンラインで行えるユーザー向けのシステムになっています。

  マイアトリエ

では実際にアイテムを作ることを想定しながら、マイアトリエを紹介します。

ちなみに、シタテルで生産できるアイテムや生産の流れを知りたい方は是非こちらをご覧ください。

シタテルで衣服を生産する流れ

シタテルで生産可能なアイテム

相談をはじめる

シタテルにご相談いただくのはとても簡単です。

1. お問い合わせの種類を選択

  マイアトリエ

2. お問い合わせ内容のタイトルを記入

  マイアトリエ

3. お問い合わせの詳細を入力

  マイアトリエ

たったの3ステップです。

詳細入力では画像などのファイルも添付できます。

アイテムの作成を希望される方は、似ているものの写真や図面などを添付していただくと、イメージがより伝わりやすくなります。

ご相談いただいた内容に対して、弊社のコンシェルジュがご返事します。コンシェルジュは衣服生産の業界でしっかりとした経験がありますので、信頼してお任せください。

相談を続けてアイテムの詳細を固める

ご相談内容に対してコンシェルジュがお見積りや生産に関するサポートを行います。

  マイアトリエ
  マイアトリエ

チャットの形式で進んでいきますので、スマートフォンなどで確認しながらすばやく相談を行えます。

詳細が決まったら生産の状況を確認しながら進める

衣服生産では、サンプル作成、本生産という2段階の流れを取ります。

各アイテムがどのような状況であるかが共有され、必要に応じてトピックで追加のご相談をいただけます。

  マイアトリエ
  マイアトリエ

複数のアイテムの進捗も確認できます。

  マイアトリエ

以上が、シタテルでのアイテム作成手順です。

工場との連絡や交渉、記事資材の手配などはコンシェルジュが全て行えますので、はじめての生産でも失敗すること無く進められるようになっています。

フロー情報とストック情報

シタテルでは、 コミュニケーションによって生まれる情報の伝達をフロー情報、その結果として決定されることをストック情報として、それぞれが気持ちよく扱えることを意識してシステムの開発を行っています。

ユーザーの方に沢山のボタンから選ばせたり、複雑な数値の入力をさせること無く、自然な会話の中で詳細を決定し、その情報をリアルタイムに共有します。

感性やイメージがとても大切なアパレルの世界ですので、システムによって思考が中断したり乱れたりしないように意識しています。

まとめ

第3回は シタテルがユーザーの皆さんから相談を受けるマイアトリエについて紹介しました。第4回はシタテルが連携する縫製工場に提供しているマイオペレーターについて紹介します。

お楽しみに!

, ,

2018年11月16日金曜日

githubイシュー/PRの管理にjasperを導入したら幸せになった話

こんにちは!

シタテルで エンジニアをしている建山です。

主に工場向けのマイオペというシステムの開発を行っています。

シタテルではgithubを使ってソースコード・イシュー/PR管理などをしています。
その中で、困るなとおもっていたのがイシューへのアサインやコメントに気づく仕組みでした。
PRやイシューで自分にアサインやコメントされているにもかかわらず、気づくかない、気づくのが遅くなるなど、あげくのはてに、slackでメンションもらったりということもありました。

そこで、リアルタイムに通知を受け取ったり、メンションにもれなく気づけるようになりたいとおもっていたところ、社内のエンジニアにjasperよさそう!とおしえていただいて実際便利でしたので紹介します。

jasper以外にもいい方法はいくつかあるとおもいますが、今回はjasperを使った方法を記載します。

jasperとは

githubのイシュー/PRを閲覧や管理をしやすくするソフトウェアです。
Mac版/Windows版/Linux版があります。
https://jasperapp.io/

cookpadのエンジニアの方がつくられているようです(https://techlife.cookpad.com/entry/2017/03/14/100000

ほとんどここに書かれています。

jasperを使った方法

jasperにはstreamsを登録する機能があります。こちらに登録しておくと、
条件ごとに一覧で見ることができて、通知を受け取りたい場合は、特定のstreamだけ通知を受け取るということもできます。

私が通知を設定しているstreamsはこちら。

公開中のイシューで自分にメンションもらっているリスト

is:issue is:open mentions:ユーザー名

公開中のイシューで自分に レビューリクエストもらっているリスト

is:open is:pr review-requested:ユーザー名

PRで自分にアサインもらっているリスト

is:open is:pr assignee:ユーザー名 archived:false

公開中のPRで自分にメンションもらっているリスト

is:pr is:open mentions:ユーザー名

まだ使いこなせていないのですが、ほかにもたくさんの用途にstreamを分けることができます。
https://jasperapp.io/doc.html#stream

個人的には、jasperを使いだして、github上でするべきコメントを、slack上でやることが減ったと感じています。github上にもコメントで経緯ものこるので、いいなと感じています。

日々、改善しながらやっていきたいと思います!

, , , ,

2018年11月15日木曜日

SQLite3でWindow関数を試してみた!

SQLite3

はじめまして、DevOpsチームの甲斐です。
何かブログのネタはないかなーと思っていたところ、たまたま以下のニュースを発見しました。

ウィンドウ関数サポートが加わった「SQLite 3.25」公開

Window関数というとちょっと前までフリーなRDBMSでサポートしているのはPostgreSQLの一択でしたので、
「SQLiteでWindow関数が使えるようになったのか!」とちょっとした驚きでした。
(ちなみに、MySQLでもバージョン8からWindow関数が正式に実装されたようです)

そこで、今回はこの新機能である「SQLiteでWindow関数」を試していきたいと思います。

SQLiteのインストール

何はともあれSQLiteをインストールしましょう。
SQLiteでWindow関数を試すには9月にリリースされた3.25以上が必要ですので、最新のSQLiteをインストールします。
以下は、Macでの手順です。Windowsな方は適宜インストールして下さい。
また、Macなエンジニアの方はすでにHomebrewはインストール済みかと思いますので、Homebrewのインストール手順は割愛します。

% brew install sqlite
% echo 'export PATH="/usr/local/opt/sqlite/bin:$PATH"' >> ~/.zshrc  # bashな方は.bashrcで
% exec -l $SHELL

SQLiteのバージョンが3.25以上であればOKです。

% sqlite3 --version
3.25.3 2018-11-05 20:37:38 89e099fbe5e13c33e683bef07361231ca525b88f7907be7092058007b75036f2

SQLiteでWindow関数を使ってみる

それでは、SQLiteでWindow関数を試してみたいと思います。

Window関数とは

そもそもWindow関数とは何かというと、

SQL において、窓関数もしくはウィンドウ関数 (英: window function) は結果セットを部分的に切り出した領域に集約関数を適用できる、拡張された SELECT ステートメントである。SQL:2003 以降の標準SQLで規定されている。分析関数やOLAP機能と呼ばれる場合もある。

(by Wikipedia)

とあります。
いまいち要領を得ませんが、要は分析に使えるSQL関数ということですね。
エンジニアの皆さんもご自身でちょっとした分析などをやることもあるかと思いますが、その際にWindow関数を知っていると結構便利です。

日経平均株価の移動平均を求めてみる

今回はサンプルとして日経平均株価の移動平均をSQLiteのWindow関数で求めてみたいと思います。
「移動平均」をWikipediaで検索すると、

移動平均は、時系列データ(より一般的には時系列に限らず系列データ)を平滑化する手法である。音声や画像等のデジタル信号処理に留まらず、金融(特にテクニカル分析)分野、気象、水象を含む計測分野等、広い技術分野で使われる。有限インパルス応答に対するローパスフィルタ(デジタルフィルタ)の一種であり、分野によっては移動積分とも呼ばれる。

主要なものは、単純移動平均と加重移動平均と指数移動平均の3種類である。普通、移動平均といえば、単純移動平均のことをいう。

(by Wikipedia)

とあります。
もう少し具体的に説明すると、例えば3日間移動平均を求めるとは以下のような感じになります。

date        sales   d3_moving_average
2018/11/01  100     100.0
2018/11/02  110     105.0
2018/11/05  120     110.0               # 11/01-053営業日のsalesの平均
2018/11/06  80      103.333333333333    # 11/02-063営業日のsalesの平均
2018/11/07  150     116.666666666667    # 11/05-073営業日のsalesの平均
2018/11/08  200     143.333333333333    # 11/06-083営業日のsalesの平均
2018/11/09  100     150.0               # 11/07-093営業日のsalesの平均

これを素のSQLだけでやるのはけっこう大変なのですが、Window関数を使うと簡単にできます。
それでは実際に日経平均株価の5日間移動平均をWindow関数で求めていきたいと思います。

  1. 日経平均株価のデータをダウンロードします
% curl -LO 'https://indexes.nikkei.co.jp/nkave/historical/nikkei_stock_average_daily_jp.csv'

注: ダウンロードしたデータの最終行に著作権が明記されています。取扱いにはご注意下さい。

  1. ファイルがWindows仕様になっているのでMac(Unix)仕様に変換します
# 文字コードをShift-JISからUTF-8へ変換
% iconv -f cp932 -t utf-8 nikkei_stock_average_daily_jp.csv > nikkei_stock_average_daily_jp-utf8.csv

# 改行コードをdos(CRLF)からunix(LF)に変換
% perl -i.bak -pe 's/\cM//g' nikkei_stock_average_daily_jp-utf8.csv

# ヘッダが日本語なので英語に変換
% perl -i.bak -pe 's/^.*$/date,end,start,high,low/ if $. == 1' nikkei_stock_average_daily_jp-utf8.csv

# 最終行の著作権の文言を削除
% perl -i.bak -ne 'print $_ if !eof' nikkei_stock_average_daily_jp-utf8.csv
  1. CSVファイルをSQLiteにインポート
% sqlite3
sqlite> .mode csv
sqlite> .import ./nikkei_stock_average_daily_jp-utf8.csv nikkei
sqlite> .schema nikkei
CREATE TABLE nikkei(
  "date" TEXT,
  "end" TEXT,
  "start" TEXT,
  "high" TEXT,
  "low" TEXT
);
  1. 2018/09/01以降の日経平均株価の5日間移動平均を求めてみる
sqlite> .headers on
sqlite> select
   ...>   date,
   ...>   end,
   ...>   avg(end) over(
   ...>     order by date
   ...>     rows between 4 preceding and current row
   ...>   ) as d5_moving_average
   ...> from
   ...>   nikkei
   ...> where
   ...>   date >= '2018/09/01'
   ...> ;
date,end,d5_moving_average
:
(snip)
:
2018/11/02,*****.**,21691.772
2018/11/05,*****.**,21841.61
2018/11/06,*****.**,21979.702
2018/11/07,*****.**,22012.77
2018/11/08,*****.**,22172.624
2018/11/09,*****.**,22173.942

注: 日経平均株価は著作権により転載が禁止されているためマスクして表示しています

avg(end) over(...)の部分がWindow関数部分です。
over()の部分でグループ化を行い、そのグループに対してavg()を適用するという感じになります。
ここでは、全体の集合(select date,end from nikkei where date >= '2018/09/01')に対して、
まずdateでソートして、現在行より4行前(4 preceding)から現在行(current row)までの5日間の平均(avg(end))を
一日ずつずらしながら順次求めていることになります。

この他にもWindow関数には便利な機能が沢山ありますので、是非いろいろと調べてみて下さい。
また、最近のSQLiteはJSON型もサポートされいていたり結構高機能ですので、こちらも是非ご活用下さい!

, ,

2018年11月14日水曜日

リリース作業を少し楽にした開発(Slack+Lambda+Golang)

こんにちは、シタテルの鶴巻です。

devops&インフラ担当です。

シタテルのプロダクトのリリース作業を少し楽にするために、
Slack+Lambda+Golangを用いて開発した話をします。

リリースの流れ

シタテルでは、GitフローやGitHubフローを採用しています。

また、本番環境へのデプロイは、以下の流れで実施しています。

  1. developブランチからreleaseブランチを作成
  2. ステージング環境でreleaseブランチをデプロイ&動作確認
  3. 本番環境にデプロイ

ちなみに、1.でreleaseブランチを作成すると、CircleCIによって2.のステージング環境へのデプロイは自動で行われます。

地味に面倒なリリース作業

ステージング環境へのデプロイは自動化されているとはいえ、小さな手作業が合間に発生し、地味に面倒でした。

具体的には以下のような作業です。

  • developブランチからreleaseブランチの作成
    • ローカルPCでdevelopブランチを最新の状態にpullして、releaseブランチ作成してGitHubにpush
  • releaseブランチのプルリクエスト作成
    • GitHubのUIをポチポチ
  • リリースタグの作成
    • 前回のリリース以降でマージされたプルリクエストを見て、リリース内容を記述

手作業はSlackからコマンドを叩くだけにしました

Slackから以下のコマンドを叩くだけで、地味に面倒くさかった作業を自動で行うようにしました。

/release <repository> <release branch>

実際には、以下の内容を実施するGolangプログラムをLambdaで実行しています。

  • 対象のリポジトリをクローンし、developブランチからreleaseブランチを作成し、GitHubにpush
  • releaseブランチのプルリクエストを作成
  • 前回のリリース以降にマージされたプルリクエストのタイトルのリストを記述したリリースタグのドラフトを作成

構成

Slack -> API Gateway -> Lambda01(同期) -> Lambda02(非同期) -> GitHub
  1. Slackからコマンドを叩くと、Lambda01にリクエストを送信します。
  2. Lambda01は、Lambda02に対象レポジトリとブランチ名を付与してリクエストを送信します。
  3. Lambda02で作業を実行します。

Lambdaを2つ使用している理由

Slackはリクエスト送信後3秒でタイムアウトするためです。

実行したいプログラムは3秒以上かかるため、実際の作業は非同期で実施する必要がありました。

そのため、Lambda01はLambda02に処理を投げて、Slackに200を返し、実際の処理はLambda02で実施します。

Lambda01はLambda02を非同期実行で呼び出すので、リクエストをキューに入れた後は、Lambda01は関数を終了することができます。

Lambdaの呼び出しタイプ(同期・非同期)

Lambdaは、呼び出しタイプ(InvocationType)を指定することで、同期実行や非同期実行を選択することができます。

例:InvocationTypeで"Event"を指定することで、非同期実行でLambdaを呼び出せます。

input := &lambda.InvokeInput{
FunctionName: aws.String("xxxx"),
Payload: jsonBytes,
InvocationType: aws.String("Event"),
}

※同期実行は"RequestResponse"を指定します

今回使用したGitHub操作のためのGoライブラリ

その他ハマったポイント

  • APIGatewayの統合リクエストのマッピングテンプレートを使いこなせず。デバッグのやり方もわからず、使うのを諦めました。

まとめ

  • 少しの手間が自動化されるだけで、すごく楽になります。これからももっとやっていきたいです。
  • GitHub操作のライブラリはとても便利でした。
  • シタテルのサービスはRails + vue.jsが主ですが、自分の好きなGo言語を使えたので楽しかったです。

参考

slack slash-command

Lambda 呼び出しタイプ

, , , , , ,

2018年11月13日火曜日

Macでの作業をちょっと楽にする7つ道具

こんにちは、シタテルの朝野です。
DevOpsやインフラ部分を担当しています。

今回はMacBookでの作業をちょっと楽にするアプリを紹介したいと思います。

本格的に開発をMacでするようになって2年ほどなのでまだまだMac界を知らないところもありますが、役に立てばうれしいです。

7つ道具とは!

Karabiner

https://pqrs.org/osx/karabiner/

キーの入れ替えや修飾キーがらみの動作をカスタマイズできます。
ちなみに私は

  • 左CapsLock -> 左Command
  • 左Command -> 左Control
  • 左Control -> 左CapsLock

という修飾キーローテーションをしていたりします。

AppCleaner

http://freemacsoft.net/appcleaner/

アプリケーションを「完全に削除」するアプリです。
アプリ本体に加え、設定ファイルやユーザーデータ等も一気に削除できます。
掃除をするなら徹底的にしたいですね。

Alfred

https://www.alfredapp.com/

Mac使いにはおなじみの帽子マークのアプリです。
アプリケーションの起動やファイル検索、Web検索、電卓など機能を素早く呼び出せます。
ほぼアプリケーションランチャーとしてだけ使っているのでもう少し使いこなしを覚えたいです。

Clipy

https://clipy-app.com/

クリップボードにコピーした履歴を保存して、呼び出せます。
いろんなところから何度もコピペをしていると、コピー元がどこだったかわからなくなることあるますよね?

GIPHY CAPTURE

https://giphy.com/apps/giphycapture

デスクトップの任意の領域を録画してgifアニメーションのファイルに保存できるツールです。
アプリケーションの修正した部分の動作なんかをキャプチャしてプルリクエストに添付しておくとレビューがはかどります。

Macs Fan Control

https://www.crystalidea.com/macs-fan-control

温度管理アプリです。
回転数や基準温度を設定して冷却ファンの動作を調整したり、メニューバーにCPU等の温度を表示できます。
MacBookで目玉焼きが作れそうなときにぜひ。

FlagSwitcher

https://itunes.apple.com/jp/app/flagswitcher/id1157313107?mt=12

入力言語を切り替える際にチラッと国旗を表示するだけのアプリです。
だけなんですが、今入力モードを何にしたのかがわかると少しだけタイピングの効率が良くなります!💪🏻

まとめ

今回はMacの基本操作やシステム系のアプリを紹介しました。
普段のちょっとした作業を楽にするのもDevOps!
とまでは言いませんが、開発系のアプリ紹介なども考えているのでまた記事にできればと思います!

, , ,