taiki-t's diary

きぎょうにっき, React Native, Rails そして雑多な記録: The world is waiting for you to give it the meaning.

技術コミュニケーションでは「良いと思うので」に理由を添えて生産性を高めよう

「こちらの方が良いと思うのでこうします!」

「これはあんまりよくないと思うので」

というやり取りはよくある。自分も気を抜くとやってしまう。 これは暗黙的に「良い」の概念が共有されていると思いやってしまいがちだが、必ずしも共有されているわけではない。

「こちらの方が良いと思うので」とだけ言われた方は、「何で???」と思っているかもしれない。

ので、「良いと思う」だけで終わらせることはせずに、代わりに明確にその根拠を含める、添えるようにする。 そうすることで、より意図を明確に伝えることができる。 また、何をもって「良い」と考えているか伝えることでより的確なフィードバックを得ることができる。

1

  • x「こちらのデザインの方が良いと思うのでこれで行きます。」
  • ○「こちらのデザインの方がユーザーに意図を明確に伝えられて良いと思うのでこれで行きます。」

2

  • x「このコードはこっちの方が良いと思います」
  • ○「このコードはこっちの方がメンテナンス性が高くて良いと思います」

上記のように理由を添えることで、コミュニケーションのステップも縮めることができる。 相手の意図を把握できずモヤモヤした場合「何が良いのですか?」からいちいち探らなくて良い。 理由が気になった場合には 「どうしてこちらの方が意図を明確に伝えられるんですかね?」や「なぜメンテナンス性が高いんですかね?」 と、そのようにすぐコミュニケーションを進めることができる。 理由が気にならない場合は、OKの旨を返事すればそれで事足りる。

現場にて

  • コードレビューで: 「これは良くないと思います」だけのコメントは生産性を下げる行為なので、必ず理由を添えるようにしよう
  • コードコメントで: 「FIXME: このコードはよくない」みたいなのは何が良くないか忘れるし見た人もわからないので、理由を添えよう
  • Slackで: 賞賛以外の「良いと思います」には理由を添えよう

ターミナルでgit grep して一括置換するコマンド

$ git grep -l 'search word' | xargs sed -i '' -e 's/search word/replacing word/g' 

こんな感じ。 search word, replacing wordはそれぞれgrepする語、置換後の語を指定。

git grep -lで対象の語が含まれるファイル一覧を取得、 | xargsでそれを sedコマンドの引数渡す。 sed -i でインプレイスで置換。

React Native Tab View with default index to 1

When Using React Native Tav View with defalut index to 1, I happened to face a strange behaviour; automatically swipes to index 0 sometimes when opening the scene. So what I did was to set initialLayout and it fixed it.

Like this:

const initialLayout = {
  height: 0,
  width: Dimensions.get('window').width,
};

render () {
   <TabViewAnimated
       // other props
       initialLayout={initialLayout}
   />
}

github.com


React Native Tab Viewの初期indexを1に指定して使ったところ、画面を開いたとき時々勝手にindex 0の画面にスクロールされることがあった。 initialLayoutを設定したら解決した。

React Nativeで画像のトリミング(cropping)

React Nativeで画像のトリミングができる。特に外部のコンポーネントを入れる必要はない。

標準の ImageEditor を使ってできる。

しかしながらいかんせんドキュメントが少ないのでここに記録も兼ねて残そうと思う。

※ 記事執筆時に使用したReact Nativeのバージョンは 0.44.0

ImageEditorの使い方

これはドキュメントにある通りだけど、シグネチャは以下の通り

static cropImage(uri, cropData, success, failure)

トリミングしたい画像のuriを渡して、あとはトリミングの設定と成功、失敗時のコールバックを渡す。

Promiseでつつむ

コールバックを渡す形式だとコードの見通しがよくないので以下の通りPromiseで包んで使うことにする。

// Reactコンポーネントの中
_crop(uri, cropConfig) {
  return new Promise((resolve, reject) => {
    ImageEditor.cropImage(uri, cropConfig, resolve, reject)
  })
}

これで、呼び出し時にはthis._crop(uri, cropConfig)とだけやってあとはasync/awaitの流れで処理すれば良いようになった。

オプションの設定

シグネチャにはcropDataとあるけどcropConfigの方が個人的にはわかりやすかったのでコード例中ではそういう名前で使っている。 このcropConfigに指定する値の例を示すとこのようになる

cropConfig = {
  offset: {
    y: yOffset,
    x: xOffset
  },
  size: {
    height: alteredHeight,
    width: alteredWidth,
  },
}

オプションの詳細については: https://github.com/facebook/react-native/blob/9ee815f6b52e0c2417c04e5a05e1e31df26daed2/Libraries/Image/ImageEditor.js#L16

上記のようなものを用意してthis._cropに渡す。 これとasync/awaitのことも合わせ、画像をトリミングする全体的な流れは次のようなメソッドになる。

// Reactコンポーネントの中

async _cropImage(imageUri) {
  try {

   let cropConfig = {/*offset, size を指定*/}

   return await this._crop(imageUri, cropConfig)
  } catch (error) {
     console.log(error)
  } 
}

offsetの指定の仕方

ImageEditorを使うときの全体の流れは上述の通り。ここでは、トリミングする際のoffsetの設定についてかく。 offsetは上記cropConfigで渡すもの。

offsetはトリミング前画像の左上隅からの距離になる。図示すると以下の感じ。

f:id:taiki-t:20170706160138p:plain

ので、上記のように中央でトリミングする場合、x軸側のoffsetは

(元画像の横サイズ - トリミング後画像の横サイズ) / 2

とかで求められる。y軸は0

画像サイズの取得

上記のところまで、やって、「で、どうやって元画像のサイズを取得するの?」というのがあると思うのでそこについて少し。 ImagegetSize関数を使う。

https://facebook.github.io/react-native/docs/image.html#getsize

これもPromiseでラップしてやればいいと思う。

_getSize(uri) {
  return new Promise((resolve, reject) => {
    Image.getSize(uri, (width, height) => { resolve({width, height}) }, reject)
  })
}

それで、使うときはこんな感じ

let { width, height } = await this._getSize(imageUri)

画像の削除

と、一点注意が必要だった。トリミングされた画像はImageStoreに保存されているので、cropImageの戻り値として返されるuriをstateなりに保存しておいて、アップロードなど必要な処理が終わったときはImageStoreから消しておく。 こんな感じ。

ImageStore.removeImageForTag(this.state.imageData.uri)

参考リンク

https://facebook.github.io/react-native/docs/image.html#getsize

ImageEditor

ImageStore

react-native/ImageEditor.js at 9ee815f6b52e0c2417c04e5a05e1e31df26daed2 · facebook/react-native · GitHub

React Nativeで動いている実例はこのアプリで: Lylica 「近くの今が分かる」位置情報SNS

このアプリでは画像のトリミングのほか、リサイズもしている。リサイズには GitHub - bamlab/react-native-image-resizer: 🗻 Resize local images with React Native を使っている。

heroku で定期dbバックアップ

$ heroku pg:backups:schedule DATABASE_URL --at '02:00 Asia/Tokyo' --app your_app_name

これだけだった。簡単

devcenter.heroku.com

TimeZoneの表記はここから

https://en.wikipedia.org/wiki/List_of_tz_database_time_zones

React NativeのImageを使うときの注意

React Native のImageを使うときの注意

とりあえずImage要素にサイズ(widthとheight)は指定する。じゃないと表示されない。

バージョン: 0.44.0


追記: 2017/07/07: 0.47.0以降のバージョンでこの制約は消えそう。Using <Image> with nested content now causes warning (yellowbox) · facebook/react-native@279f5f1 · GitHub

React Native のTouchableなんとか使うときの注意

TouchableWithoutFeedbackとか使うとき、 とりあえず内部の要素はTextだろうがImageだろうがViewでラップしておくのが無難。 余計なハマりポイントを回避できる。

バージョン: 0.44.0