バグですか?仕様ですか?筋肉です💪

筋肉とプログラミング、その他アウトプットをしていきます。

10倍速く文章を書く方法

Slackなどのチャットツールが広まり、短い文は書くけど「文章」を書く機会は以前より減ってしまいました。

いざ、ちゃんとした文章を書く機会に出くわすと、

「長い文章書きたくない、、、チャットでいいじゃん」
「何から書けばいいかわからん、、、」
「読み返したら意味不明、また書き直さなきゃ、、、」

などと文章を書くことが苦痛で仕方ない人がいらっしゃると思います。

また、苦痛ではなくても「より短い時間」「わかりやすい」文章を書きたいと誰もが思うのではないでしょうか?

今回は、そんな人のために、「10倍速く書ける超スピード文章術」という本を紹介したいと思います。

「わかりやすくて」「役に立つ」文章を「速く」書くにはどうすればよいかまとめていきます!!

10倍速く書ける 超スピード文章術

なぜ書くのに時間がかかってしまうのか

そもそもなぜ書くのに時間がかかってしまうのでしょうか。

読者が知りたいのは必要な情報で、それが伝われば良いのです。

しかし、言い回しはどうしたらいいかなどと表現に凝ってしまい上手く書こうとするから迷い、時間がかかってしまいます。

また、本来伝えたい内容も相手に伝わらずにわかりにくい文章になってしまいます。

文章を速く書くたった一つの秘訣は「素材」を意識すること

素材とは

  • 独自の事実
  • エピソード
  • 数字

といった読み手に伝えたい内容そのものです。

伝えたい内容がわかっている、つまり素材が準備できていれば速く書くことができます。

例えば、
自分で家を建てる場合、土台を作るときにセメントを用意する。
柱を建てるときに木材を調達する。材料を切るときにノコギリを持ってくる、、、、

といった具合にその時々に準備すると途方もなく時間がかかると思います。

速く家を建てたいのなら、まず必要な材料(素材)を準備して作業に取りかかる方が早いです。

これは文章でも同じで、まず素材を準備することで文章を速く書くことができます。

文章を書くことが決まった瞬間から、常にアンテナを立てる。そしてどんどん素材を集める。 そうすれば、素材が揃い、迷わずに速く書ことができます。

大切なのは文章の表現ではなく、文章の中身、つまり「素材」です。

「どう書くのか?」ではなく「何を書くか?」に集中することが文章を速く書く秘訣です!!

素材を使って速く書く具体的な方法

では、具体的に素材を使って速く書くにはどうすれば良いかというと、以下の手順で行っていきます。

  1. 書く目的と読者を定める
  2. 素材を集める
  3. 素材を組み立てる
  4. 一気に書き切る
  5. 見直す

1. 書く目的と読者を定める

文章の目的を定める

まず文章の目的(何のためにその文章を書くのか)をはっきりさせます。

書く前からすでにわかっている文章の目的を「表面上の目的」、そこから「真の目的」(その文章を読んだ読者に何を感じてもらいたいか)まで掘り下げます。

例えば、
表面上の目的:ブログを書く
真の目的:読者に役に立ったと言われたい 自分はこういうこともやっていると知ってもらいたい

真の目的まで掘り下げる作業は1人でできる場合もあれば、誰かに質問しないと行けない場合があります。

その場合は、依頼者に真の目的を確認しましょう。

素材を集める前に、「真の目的」を確認することを習慣にしましょう。

最もやってはいけないことは目的が定まらないまま文章を書くことです。 目的を決めずに書くと「文章を書く」という行為自体が目的になってしまうからです。

大事なのは上手い文章を書くことではなく「真の目的」を達成することです。

読者を定める

次に読者を決めましょう。

なぜ読者を決めるかというと相手によって素材が変わってしまうからです。

例えば、
技術の話をする場合に、非エンジニアに対して専門的な言葉を使ってしまうと相手はちんぷんかんぷんです。
逆にエンジニアに専門的な言葉を使わずに話すと、この人はあまりわかっていないんだなと思われるかもしれません。

書き手として意識することは読者の役に立つものになっているか、素材がわかりやすく伝わるかです。

また、自分にとって面白いことが、必ずしも読者にとって面白いわけではありません。

読者の知識レベルや興味関心に応じて何が面白いかを考えることで、適切な素材をピックアップできます。

では、不特定多数の読者がいた場合はどうすれば良いでしょうか?
例えばブログなど。

その場合でも特定の読者を決めることが必要です。

年齢、属性で特定の層をイメージします。時には読者の悩みに踏み込んでイメージすることもあります。

例えば、
20代男性エンジニア 書いた文章が相手に伝わらないことに悩んでいる

あなたの文章を読む人は個性を持った1人の個人なので、みんなに伝わる文章を書こうとすると結果的に誰にも伝わらない可能性があります。

2. 素材を集める

次に、素材を集めましょう。

書き始めてから素材を集めようとすると時間的にも精神的にも大きな負荷がかかります。
素材は早めにたくさん集めてあとで削ると良いです。

集め方としては、単純にメモをとりましょう。
人間の記憶はあてにならないので、その場で見たもの聞いたこと感じたこと全てメモしましょう。(私の場合は、本を読み進める中で本文に線を引いて素材を集めていました。)

素材を書き出す際には使えないとか考えずに思いついた順に書き出しましょう。

f:id:takuma521:20200209130630p:plain
実際に素材を書き出したもの

特に自分の見た情報、体験した情報もメモを取り、文章に盛り込むことで読者に臨場感を伝えられます。
書き手が体験したことは文章の中にインパクトを与え、他の人には出せないその書き手だけの説得力が生まれます。

3. 素材を組み立てる

次に集めた素材を組み立てましょう。

最初にやることは集めた素材を全て見えるようにしましょう。テキストファイルに全て書き出すなど。

面倒臭がって素材を書き出す手間を省くと素材が足りなくなって拾い集めに戻るという手間が生まれます。
それが書き上げるスピードを落とす原因になるのです。

次に実際に組み立てていきます。 スラスラ理解できる文章を書くには、読者が目の前にいて、その人に話すつもりで素材の順番を考えていきましょう

会話では相手に伝わらなかった場合には、

「ちょっと何言ってるかわからない」

など相手からすぐ反応があり、言い直せますが文章ではそれができません。

ロジカルシンキングや文章の型にはめなくていいので、目の前の相手に伝わるように素材を組み立てるとその人にもっとも伝わりやすい論理が生まれます

文章のはじめ

そもそも、誰も積極的に文章を読みたがっていません

なので、書き出しがつまらない文章が最後まで読まれる可能性は低いです。

代表例は「私は」から文章です。私が書いているのだから書かなくてもわかります。
このような不要なものは書かないようにしましょう。

書き出しの役割はその先を読みたいと思ってもらうことです。

文章のはじめは、もっとも共感できる素材、印象深い素材、気になる素材を配置すること。

そうだよね、ふむふむ、へえ、お!、えっ?、なんだそれ?、しゅごい!!!!

と思えるような内容を書き出しにぶつけましょう!!

文章の終わり

オチにこだわらずにまとめを書くと読後感が良いです。

文章の目的とは、読者にどんな読後感を持ってもらうかでなので文章の最後には結論やまとめを書けば良いです。

そうすれば、読者にこの文章が伝えたかったことが改めて伝わります。

4. 一気に書き切る

素材が集まったらさっさと書きましょう!!

速く書く最大のメリットは

  • 確実に締め切りを守ることができる
  • 追い詰められるとストレスがなくなる です。

最初から完璧を目指そうとするとスピードが落ちるので、推敲して整えることを前提に、まずは文章を書き終えましょう。

書きながら途中でなんども止まっていたら一気に読める文章になりません。

誤字も表現も書いている途中に悩まずに書きましょう。

読みやすい文章を書くポイント

  • 一文を短く
    →60字くらい

  • スラスラ読めるリズムを作る
    →ですます調の中にである超の文章を適度に織り交ぜる 似た意味のフレーズを少しバリエーションを変えて繰り返す

  • 「」の強調使用

  • だから、また、さらになどの順接の接続詞を使わない
    →冗長な印象を与えてしまう

  • 逆説の接続詞で展開を生む
    →逆説された部分が強調されリズムも生まれる

  • 難しい日本語を翻訳する

基本方針は多く書いてあとで削るなので、書いているときに全体の分量を気にしないようにしましょう。

あと、読者と目的を目に見える場所に置いておくことで途中見失わないようにできます。

5. 見直す

速く書くメリットは、文章を寝かせることができることです。

少し時間をおくことで書き手は客観的な視点を得ることができ、初めて読む人の視点で冷静に文章を修正することができます。

文章を推敲する目的は

  • 読みやすくする
  • わかりやすくする

です。

速く推敲を終えるために大きいところから取り掛かり、その後細かい箇所を見ましょう。

最初の遂行

  • 論理が正しいか
  • 説得力に欠けていないか
  • 文脈に沿った素材か
  • 一気に読めるか
  • 重複している点はないか

初見の見直しが一番読者に近い視点です。何度も見直してしまうと、その視点が薄れてしまいます。

最初は修正を加えずにピックアップするだけです。

次にようやく細かくチェックしていきます。

  • 意味不明な箇所はないか
  • 説明不足な箇所はないか
  • 読者、文章の登場人物に失礼な言い回しがないか
  • 読者に嫌悪感を与えないか

素材が的確に伝わっているかどうか以外に読者に不快感を与えないかも重要です。

ボリューム調整は終盤にやります。

そして最後に誤字脱字を修正していきましょう。

わかりやすさを確認する方法

  • 何も知らない人を前提にしているかどうか
    →専門用語が出てくると読む気が失せる人がいるから、専門用語は必ず噛み砕く

  • 意味不明な形容詞を素材に置き換える
    →形容詞だけを書いても何に感動したかが伝わらない、本来書くべきは何が面白かったか楽しかったかの理由。つまり素材 例)すごく寒い(どのくらい寒いの??)→マイナス5度(読者に想像できる寒さ)

まとめ

表現に凝ってしまから文章を書くのに時間がかかってしまう。

素材が準備できていれば速く書くことができる

手順

  1. 書く真の目的と特定の読者を定める
  2. 体験したことをメモに取り素材を集める
  3. 読者に喋って伝えるつもりで素材を組み立てる
  4. 完璧を目指さず一気に書き切る
  5. 大きい箇所から細かい箇所に向かって見直す

最後に

実際にこのやり方でこのブログを書きました。

本に線を引きながら読んだ後、素材を書き出すからブログを公開するまでには3、4時間ほどかかりました。

以前同じように本の紹介を書いた記事は2倍かかっていました。内容が難しかったというのもありますが、、、

実際に試してみて良かったことは、

  • 素材を最初に集めたことで、文章が組み立てやすかった。
  • 文章を組み立てた後は一気に書き切れた。

ただ、うまくいかないこともありました。

  • 組み立てる際に素材の繋がりがわからなくて素材集めに戻ってしまうことが何度かあった。

です。

今後も、このやり方をブログや文章を書く時には活用したいと思います! 皆さんもぜひ試してみてください!!

今回書けなかったこともあるので、ぜひ本も読んでみてください!!

10倍速く書ける 超スピード文章術

10倍速く書ける 超スピード文章術

エンジニアリング組織論への招待まとめ

はじめに

今回は、「エンジニアリング組織論への招待」という本のまとめを書いていこうと思います。

エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング

エンジニアは仕事を進めていく上でコードを書く以外に様々な問題に直面します。

  • 上司、プロジェクトメンバーとのミスコミュニケーション
  • 経営者とエンジニアとの認識の食い違い
  • スケジュール通りに終わらない

これらの根源は「わからない」ことへの不安です。
この本はその不安、つまり不確実性とどう向き合っていくかについて書かれています。

今回は、1章の思考のリファクタリングについてまとめていきます!

この記事を読んでわかること

  • エンジニアリングとはなにか
  • 不確実性とはなにか
  • 不確実性を下げるには

エンジニアリングとは

エンジニアリングとは、何か役に立つものを実現していくこと(曖昧さを減らし、具体性、明確さを増やすこと)です。

エンジニアリングする上で重要なのは、どうしたら効率よく不確実性を減らしていけるかです。

不確実性とは

不確実性とは、わからないことから生まれます。人間にとってわからないことは2つ

  • 未来
  • 他人

未来は、それがやってくるまでどうなるかわかりません。
頭でいくら考えていてもわからないものなので、実際に行動し、実験して観察することで少しずつ確実になっていきます。

他人も、わかりません。

私たちは1人1人別の自意識を持っていて全ての情報を一致させることは不可能です。 これもいくら考えていても決してわかるものではないので、コミュニケーションを通じて不確実性を削減するしかありません。

この2つの不確実性を減らしていくことが唯一物事を実現させる手段です。
しかし、私たちはわからないものに向き合うことを避けてしまうという習性があります。

それが不安です。

私たちは不安なものには、攻撃か逃避を選択してしまいます。なので人は自分がわかっているものを優先して実行してしまう癖があります。

不確実性が減っていかない限り不安は減りませんし、向き合おうとするとそれ自体が最大の不安を生み出してしまいます。

不確実性を下げるには

ではどうすれば良いのか。

不確実性を下げるには、情報を生み出すことが必要です。

いかにして、多くの情報を生み出すことができるのか、そのために何をすべきなのかというのがこの本の一貫したテーマであり、エンジニアリング活動の本質の1つです。

情報を生み出すには思考を前に進める必要があります。
ここでは3つの考え方を用いて思考を前に進めていきます。

  • 論理的思考の盲点を知る
  • 経験主義と仮説思考
  • システム思考

それぞれみていきましょう。

論理的思考の盲点を知る

思考を前に進めるには論理的思考が不可欠です。

論理的思考で正しい結論を導くには、

  • 事実を正しく認知できること。
  • 正しく演繹できること。

が、必要です。

(演繹は「Aである」という前提から、「Bである」という結論を導くことです。
A:人間はいつか死ぬ。B:私はいつか死ぬ)

しかし、人は論理的な思考を常に正しく使えるわけではありません。

特に他人が関わってくる問題に対しては感情的になりやすいです。

私はあなたではないという単純なことが、忘れられてしまい、自分の事情は全て相手に伝わっているのだという勘違いも発生します。

どんなに自分が正論だと思っていることも、その人自身の世界の中で認識できる範囲の中での正論にすぎず正解ではないのです。

どんな時に自分は論理的で無くなるのかを知った上で問題解決に臨む、それが論理的思考を進める上で重要なことです。

自分は論理的に考えることができると思いこむことこそが非論理的な思考を生みます。

それを踏まえた上で自分がどのようなときに認知が歪むのかを知り、自分の歪んだ認知を正すための行動を促す考え方が論理的思考の盲点を知るということです。

  • 自分がいつ非論理的になるかを知ること。
  • 自分は間違っているかもしれないが、それに早く気付く方が良いと思考のパターンを変える必要がある。

経験主義と仮説思考

情報を生み出す際に有効なのがこの経験主義仮説思考です。

経験主義

情報を入手するために行動を起こして、その結果を観察し、そこから問題解決を行う考え方を経験主義と言います。

私たちが、何か問題に出くわした時にできることとは、

  1. コントロールできるものを操作する
  2. 観測できるものの結果をみる

だけです。

コントロールできるものとは、例えば、自分の行動です。例えば毎週ブログを書くとかです。これは自分の行動次第でコントロールできます。

逆に、例えば、コントロールできないものはブログの読者を増やすことです。しかし、これは観測できることなので実際に自分がブログの書く内容を変えてみたことで結果読者が増えた減ったなどの結果を見ることができます。

経験主義は、やってみなければわからないだけの論理ではなく、上記の方法でしか前に進むことができないということを意味しています。

仮説思考

仮説思考とは、情報がわずかであってもそれを説明可能とする大胆な思考展開を行い、それを検証するための行動につなげる考え方です。

この考え方は、常に正しいわけではありませんが、今あるデータからは、演繹的に導くことのできない跳躍を生み出してくれます。

経験主義と仮説思考によって、どのような問題なのかをはっきりさせることで、同じところをぐるぐる回る不毛な思考を避けることができます。

(不毛な思考は、仕事で解決できない問題にハマってしまった時に、考えているようで考えていないような状態に近いですね笑)

  • 今直ぐに解くことのできない問題であれば、それはおそらくどのような問題かはっきりしていない。
  • 問題をはっきりさせる仮説を立てて、検証していくというプロセス思考に思考を切り替えることが大切。

システム思考

人は問題を個人の責任にしたり、全体像を見失った局所最適解な思考をしてしまいます。

それが全体像ではないかもれない、問題は関係性にあるのではないかという視点をもつことがこのシステム思考の考え方です。

私たちはつい自分から見える世界の中に閉じこもって、正しさや合理性を判断しています。
しかし、人間が認知している範囲というのは、全体のごく一部にすぎません。

問題は複雑に絡み合っている場合があります。

そのため、合理的に見える解決策が別の問題を引き起こしたり、想定していない悪化をもたらすことがあります。

このように全体像を把握できない状態で、問題解決を進めて行こうとすると思いもよらない結果を生むことがあります。

そうならないためには、

  • 対立に見える問題を対立にならない全体像をあぶりだすこと。
  • その解決を個人の問題にせず、関係性の問題に変換して本当の問題を発見すること。

が必要になってきます。

人間の不完全さを受け入れる

問題が難しく感じられているときには、まだ問題が十分に変換されていません。

この章のタイトルである思考のリファクタリングとはこの3つの考え方を用いて、複雑な問題を簡単に変換していき思考を前に進めていくということです。

自分の認知の歪みをパターンとして記憶することで過ちに気が付きやすくするという習慣を持つことができます。そうすれば少しずつ改善していきます。

コミュニケーションの不確実性

コミュニケーションの不確実性は3つの不確実性からきます。

  • 人は、他人や事象を完全に理解できない。
  • 相手に全てが正しく伝わるとは限らない。
  • また、正しく伝わったからといって、他人が思ったように行動するとも限らない。

これらの不確実性によって、さらに以下の問題が引き起こされます。

  • 自分は知っているけど他人は知らないといった情報の非対称性

→自分の抱えている状態を他人は把握しているはずだと勘違い、あるいは把握してほしいという願望に基づいて行動してしまいます。

  • 人は限られた範囲でしか合理的な行動が取れない非合理性

→複数人の共同作業では、個々人が最適だと思う行動でも、全体として不合理な行動になってしまいます。

通常エンジニアリングは複数人で何かを実現しますが、上記のために、1人ではなかなか起こらないはずの不合理な行動が、組織では発生してしまいます。

このような情報の非対称性や非合理性を起こさないためには、

意思決定とそれに関わる情報が組織内に正しく整合性をもって伝達されるように継続して努力し、何かわからない決定があったとしても直接聞いてみようという関係性を作ること

が必要です。

まとめ

エンジニアリングは何かを実現していくことで、重要なのは不確実性を効率よく削減することです。

不確実性は、わからないことで

  1. 未来
  2. 他人

から生まれます。

これらを解消するには情報を生み出すことが必要です。
つまり思考を前に進めること。

それには3つの考え方があります。

  • 論理的思考の盲点を知る
  • 経験主義と仮説思考
  • システム思考

これらの考え方を使い、自分自身の認知の歪みをパターンとして記憶することで、過ちに気が付きやすくなる習慣を持つようにします。

そうすれば、少しずつ改善でき思考が前に進むようになります。

そして、エンジニアリングは組織で複数人で行うので、 それらを行いながら同じ目的で働いているはずの人々との間にあるコミュニケーションの不確実性を減らしていく必要があります。

最後に

この本を読んで確かになぁと思うことがいくつもありました。

例えば、他人と少し言い争いになる時って、正論をぶつけているつもりですが、それって結局自分の中の正論だったり常識なんですよね。

相手もそういうものを持っていて、結局何も良くならずにお互いにストレスを溜めてしまうだけみたいな。

そういう時に、非論理的思考の盲点を思い出してこれはただ自分の正論に過ぎないんだとか、システム思考的にこのまま言い争って言い負かしても意味ないな、どうしたら本来の目的を達成できるかなと考えた方が有益です。

経験主義と仮説思考もエンジニアの仕事をする上で、大切です。

本文にも書きましたが、ずっと考えてわからないものはわかりません。

そこで、考え続ける(実際にはあんまり頭は動いていない)よりは、どんな情報があれば解決できるだろうかとか、誰に聞けばわかるだろうかとだけ考えて直ぐに行動し、その結果からまた思考をする方が問題解決にとって効率的だなと思いました。

エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング

エンジニアリング組織論への招待 ~不確実性に向き合う思考と組織のリファクタリング

webを支える技術 REST

去年読み始めたwebを支える技術でしたが、途中で放置していました。
今年は違うぞということで、ここ2週間くらいで改めて最初から最後まで読み通しましたので、そのアウトプットとして今回記事を書こうと思います!

今回はRESTについてです!!

この記事を読んでわかること

  • RESTとはなんであるか。RESTを構成するアーキテクスチャスタイルについて。

REST

RESTは複数のアーキテクチャスタイルを組み合わせた複合アーキテクチャスタイル。
アーキテクチャスタイルと言う言葉がいまいちピンとかなかったけど、調べてたら設計思想というのがなんとなくしっくりきました。

リソース

リソースについては過去の記事で書いてありますので、そちらを!

HTTPとは - バグですか?仕様ですか?筋肉です💪

RESTを構成するアーキテクチャスタイル

クライアント/サーバ

クライアント側とサーバ側で分けることでつまり、ユーザーインターフェースと処理を分けることです。
これによりwebにpc以外でアクセスすることができます。また、複数のサーバを組み合わせることで可用性(システムが継続して稼働できる能力)を上げられます。

ステートレスサーバ

クライアントのアプリケーションの状態をサーバ側で管理しないことです。そうすることでサーバの実装を簡略化できます。ただcookieはステートフルなものです。 ↓過去に例を交えながら説明しています!

HTTPとは - バグですか?仕様ですか?筋肉です💪

キャッシュ

一度取得したリソースをクライアント側で使い回すことです。
何度も通信をしないで済むが、古いキャッシュにより情報が間違っているかもしれないので注意です。

統一インターフェース

URIで指し示したリソースに対する操作を統一したインタフェースで行うことです。
分かりづらいので例を上げるとHTTPは8つのメソッドだけしかありません。少なすぎて使い勝手が悪いように思われるかもしれませんが、これにより対応しなくてはいけないものが少なくなり、結果としてシンプルにすることができます。

階層化システム

サーバとクライアントの間に負荷を分散してくれるロードバランサを置いたり、アクセスを制限してくれるプロキシを置いたりすることです。
これは統一インターフェース(インターフェースをHTTPで統一)のおかげです。

コードオンデマンド

プログラムをクライアントにダウンロードして実行することです。例えばJavaScriptなどがあげられます。

最後に

以上、今回はRESTについてまとめてみました! RESTってよく聞くけど、それってどういうものなの?っていうのが今まで曖昧でしたが、改めて理解することができました。

私は、業務で主にRubyrails扱っています。railsは便利なので、webのことを理解していなくてもなんとなく書けてしまうのですが、このwebを支える技術を読んで、URIやHTTPを理解してから、このリソースを更新したいからここにリクエストをしないといけないんだなとか、ルーティングはこう書かないとなとかがわかるようになりました。

本を読むだとか、アウトプットをするということを続けるのは大変ですが、仕事に直結しますし自分をより良くすること、(つまり筋トレと同じ)なので今後も続けて行きたいと思います!!(^∀^)ᕗ

クールなURIとは

前回と引き続き

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

の本からURIについて書いていきます!!

この記事を読んでわかること

  • なぜ変わらないURIはクールなのか
  • 変わりにくいURIするには
  • URIを変えなくてはいけない時はどうするか

なぜ変わらないURIはクールなのか

変わらないURIがクールである

という言葉があります。なぜ変わらないURIがクールなのでしょうか?

Webはそれぞれのリソースに他のリソースが埋め込まれたハイパーメディアシステムのため、URIを変更しリンク切れを起こすと機能しなくなってしまいます。

通常ユーザは、ページにあるリンクをクリックすることで、見たいページに遷移します。 しかし、そのリンクのURIが変わってしまうとユーザはページ遷移ができなくなってしまうので、webとして機能しなくなってしまうのです。

つまり、URIは出来るだけ変わらないものが好ましい(クールである)のです。

本では主に3つ紹介されていましたので、ダメなURIを例にあげて説明していきたいと思います。

プログラミング言語に依存した拡張子やパスを含めない

http://example.jp/login.pl

例えばこのURIの場合、.plというPerlというプログラミング言語のソースに使われる拡張子が使われています。
もし仮に、PerlからRubyに言語を変えてアプリケーションを実装するとなると、URIを変更しなければなりません。 (.plでRubyスクリプトを動かすこともできますが、あまりよくはありませんよね。)

このように実装言語に依存した文字列をURIに含めてしまうと、言語を変更した際にそのURIは使えなくなってしまします。

メソッド名やセッションIDを含めない

http://eample.jp/Login.do?action=showPage

.doという拡張子も問題ですが、今回はshowPageが問題です。これはメソッドの名前なのですが、 もしリファクタリングを行なってメッソド名を変更してしまうとURIも変更になってしまいます。

セッションIDの場合、

http://example.jp/home.jsp?jsesionid=123456789

セッションIDをCookieではなくURIに埋め込むとログインのたびにセッションIDは変わるので、その度にURIも変更になってしまいます。

URIはリソースの名詞にする

http://example.jp/sample/people/show/1234

URIはリソースの名前です。なので本来名詞であるべきです。

あるリソースを取得するのか更新するのかは、URIで指定するのではなく、HTTPメソッドで決定されます。 つまりURIとHTTPメソッドは、名詞と動詞となるように設計されるべきで、showという動詞をURIに含めることはよくありません。

URIを変えないといけない時は?

変わらないURIがクールな理由と、具体的に変わりにくくするためにはどうするべきかについて書きました。

しかし、システムには変更はつきものであるように、URIも変更しなければいけない時があります。 その場合の対処法として、本では出来るだけリダイレクトをするようにと書かれていました。

リダイレクトとは、古いURIから新しいURIに転送するHTTPの仕組みで、リダイレクトしてあげればリンク切れでユーザが見たいページに遷移できなくなる心配も無くなります。

URI

この記事を読んでわかること

  • URIとは何か
  • URLやURNとの違いは何か
  • 実際のURLの構文はどのような構造になっているのか

URIとは

URI(Uniform Resource Identifier)とは、直訳すると「統一リソース識別子」です。

リソースは前回、説明しましたが、「web上のありとあらゆる情報」のことです。

HTTPとは - バグですか?仕様ですか?筋肉です💪

なので、URIとは「web上の情報を統一的に識別するID」のことであり、それを用いるとリソースを一意に識別することができます。

URIとURLとURN

URIと似た用語でURL(Uniform Resource Locator)やURN(Uniform Resource Name)という用語もありますが、違いは以下のようになります。

URLは、リソースの場所を指し示すもの

URNは、リソースの名前を示すもの

URIは、URLとURNを総称する名前でリソースを識別するもの

URIの構文

http://takuma:pass@blog.example.jp:8000/search?q=test&debug=true#10
※ダミーです

このURIは次のように分けられます。

  • URIスキーム:http
  • ユーザ情報:takuma:pass
  • ホスト名:blog.example.jp
  • ポート番号:8000
  • パス:/search
  • クエリパラメータ:q=test&debug=true
  • URIフラグメント:#n10

URIスキーム:http

URIスキームは、そのURIが利用するプロトコルを示すのが一般的です。
この場合は、リソースにHTTPでアクセスできることを示します。

ユーザ情報:takuma:pass

ユーザ情報は、このリソースにアクセスする際に利用するユーザ名とパスワードからなります。

ホスト名:blog.example.jp

ホスト名はDNS(Domain Name System)で名前が解決できるドメイン名かIPアドレスで、 インターネット上で必ず一意になります。

ポート番号:8000

ポート番号は、このホストにアクセスするときのプロトコルで用いるTCPのポート番号を示します。 同じコンピュータ内で動作する複数のソフトウェアのどれが通信するかを指定します。

パス:/search

ホストの中でリソースを一意に示します。 このように、ホスト名とパスを組み合わせることで、あるリソースのURIが世界中で重複せず一意になります。

クエリパラメータ:q=test&debug=true

検索サービスや検索キーワードを渡す時など、クライアントから動的にURIを生成する時に利用します。

URIフラグメント:#n10

その前までの文字列で表現するURIが指し示すリソース内部の、さらに細かい部分を指定する時に利用します。

最後に

今回も前回に引き続き、「webを支える技術」をまとめました。
少しずつでも今まで理解していなかったweb関連の用語をアウトプットしていき、使いこなせるように続けていきます💪

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

HTTPとは

この記事を読んでわかること

  • HTTPとは何か。
  • HTTPの特徴であるステートレス性とはどういうものか。

背景

Web業界に入ってから数ヶ月経ち、プログラミングのこともまだまだですが、そもそもwebの知識が乏しいと感じていたので、 今日は、HTTPについて簡単にまとめてみました。

参考:

Webを支える技術 -HTTP、URI、HTML、そしてREST (WEB+DB PRESS plus)

HTTPとは

HTTP(Hyper Text Transfer Protocol)はweb上でやり取りするリソースの表現を、クライアントとサーバの間でやり取りするためのTCP/IPをベースとしたプロトコル

と言われても、なんのこっちゃわかりません。 こういうわからない用語を調べて、さらにわからない用語が出た時は、さらにその用語を調べていくしかありません。。。 ここで出てきたよくわからない言葉、

を先に説明します。

リソース

リソースとは、web上のありとあらゆる情報。

例えば、

など。

特に、あるリソースを他のリソースと区別して指し示すときに使う名前をURIと呼びます。

クライアントとサーバ

クライアント(webブラウザ)が、情報を提供するサーバ(webサーバ)に接続し、各種のリクエストを出して、レスポンスを受け取る。 サーバでの処理に時間がかかる場合でも、リクエストを出したクライアントはレスポンスが返るまで待機する。

プロトコル

プロトコルとは、通信をする上での約束事

TCP/IP

TCP/IPとは、TCP(Transmission Control Protocol)とIP(Internet Protocol)は、インターネットの基盤を構成する重要なネットワークプロトコル。 HTMLやXMLなどのハイパーテキストだけでなく、静止画、音声、動画、Javascriptプログラム、PDFや各種オフィスドキュメントなど、 コンピュータで扱えるデータであればなんでも転送できる。

IPは、インターネット層でデータを実際にやり取りする部分を担当している。 指定したIPアドレスを送り先として、パケット単位でデータをやり取りして通信する。しかし、多数のルータを経由して最終的な送り先まで届くかは保証しない。

TCPは、IPが保証しなかったデータの転送を保証するトランスポート層に相当する。

で、ここまでを踏まえて改めて先ほどの説明を言い換えると、

HTTP(Hyper Text Transfer Protocol)はweb上のありとあらゆる情報を、クライアントとサーバの間でやり取りするためのTCP/IPをベースとした通信の約束事。

(あまり変わってない笑)

HTTPのステートレス性

次にHTTPの特徴であるステートレス性ついて触れてみたいと思います。

ステートレス性とは、サーバがクライアントのアプリケーション状態を保存しない制約のことです。 ステートレスとは、逆にステートフルという言葉がありますが、両者の違いについて日常でよくあるやりとりを例に挙げて、説明します。

Aをクライアント、Bをサーバだと思ってください。

ステートフルなやりとり

A「筋トレを教えてください!!」

B「どうして筋トレを教えて欲しいの?」

A「筋肉を大きくしたいんです!!」

B「どこの筋肉を大きくしたいの??」

A「足の筋肉を大きくしたいんです!!」

B「じゃあスクワットやろうか(^∀^)ᕗ」

A「はい!!」

ステートレスなやりとり

A「筋トレを教えてください!!」

B「どうして筋トレを教えて欲しいの?」

A「筋肉を大きくしたいので、筋トレを教えてください!!」

B「どこの筋肉を大きくしたいの??」

A「足の筋肉を大きくしたいので、筋トレを教えてください!!」

B「じゃあスクワットやろうか(^∀^)ᕗ」

A「はい!!」

このように、ステートフルなやりとりはそれまでのやりとりをずっと覚えていることを前提に会話をしています。 逆にステートレスなやりとりは、記憶することができないので、都度「筋トレを教えてください!!」を言わないと教えてくれません笑笑

側から見たら、ステートフルなやりとりの方が簡潔で良いのではと思いますが、欠点があります。

それは、サーバがクライアントのアプリケーションの状態を覚えることは、クライアントの数が増えるにしたがい難しくなるからです。

不特定多数のクライアントを相手にする場合、サーバ間でデータを同期しなければいけませんが、それが100台となるととても負荷のかかることです。 なので、ステートフルでは、サーバの数を増やしづらいのです。

その点ステートレスは、アプリケーションの状態を覚える必要がないため、サーバ側のシステムは単純になり、拡張するときにはただサーバを増設するだけで済んでしまうのです。

このように、プロトコルをシンプルに保つことで、PCだけでなく様々なデバイス上でHTTPは使われています。

最後に

本の数10ページについてまとめましたが、まだまだ浅い記事しか書けないなと思いました。 ただ、続けることが大切なので自分のできる範囲でまずはやっていきたいと思います。

Google Analytics APIを使用しページごとのセッション数を取得

この記事に書かれていること

背景

コーポレートサイトのブログ記事の人気ランキングを実装のために、ブログの記事ごとのセッション数を取得する必要がありました。

そこで、Google Analytics APIを使用しデータを取得し、実装しました。

Google Analyticsでできること。

Google Analyticsは、シェアNo.1のアクセス解析ツールで、Googleアナリティクスを使えば、Webサイト運営に必要なデータはほぼ見ることができます。

  • リアルタイムの利用状況
  • ユーザーの基本属性
  • ユーザーがどこから来たか
  • サイト内でのユーザーの動き
  • Webサイトの成果

などです。

実装

準備

まず必要な登録や、設定、情報を取得する必要がありますが、 以下の記事をご参照ください。

また今回の実装においては、大変参考になった記事です🙇‍♂️

https://qiita.com/Sa2Knight/items/0b61efc2be0bdf33ec48

https://qiita.com/ryota-sasabe/items/a5efd2aac244cfcce5c7

全体像

lib/tasks/google_analytics.rakeに具体的な処理、

lib/google_analytics_reporting.rbにGoogleAnalyticsReportingクラスを定義、

必要な情報、秘匿情報は各種ファイルに記述しました。

config/environments/

config/credentials

# lib/tasks/google_analytics.rake
namespace :google_analytics do
  desc 'update_articles_sessions_count_with_Google_Analytics'
  task update_articles_sessions_count: :environment do

    reporting = GoogleAnalyticsReporting.new(
      '2019-01-01',
      'today',
      'ga:uniquePageviews',
      'ga:pagePath',
    )
    reporting = reporting.get_reporting
    articles_pages = reporting.rows.select { |row| row.dimensions.first.match(%r{articles/.+}) }

    articles = []
    Article.published.find_each do |article|
      article = article.attributes
      article['category'] = Article.categories[article['category']]
      article['public_status'] = Article.public_statuses[article['public_status']]

      articles_page = articles_pages.find { |articles_page| articles_page.dimensions.first.gsub("/articles/",  "") == article['uid'] }
      next if articles_page.nil?
      article['sessions_count'] = articles_page.metrics.first.values.first.to_i
      articles << article
    end

    if articles.present?
      Article.upsert_all(articles)
      Article.reindex
    end
  end
end
# lib/google_analytics_reporting.rb
class GoogleAnalyticsReporting
  require 'google/apis/analyticsreporting_v4'
  SCOPE = ['https://www.googleapis.com/auth/analytics.readonly'].freeze
  def initialize(start_date, end_date, metric_type, dimension_type)
    @analytics = Google::Apis::AnalyticsreportingV4
    @client = @analytics::AnalyticsReportingService.new
    ENV['GOOGLE_PRIVATE_KEY'] = Rails.application.credentials.google_analytics[:private_key]
    ENV['GOOGLE_CLIENT_EMAIL'] = Rails.application.credentials.google_analytics[:client_email]
    ENV['GOOGLE_PROJECT_ID'] = Rails.application.credentials.google_analytics[:project_id]
    @start_date = start_date
    @end_date = end_date
    @metric_type = metric_type
    @dimension_type = dimension_type

    @client.authorization = Google::Auth::ServiceAccountCredentials.make_creds(
      scope: SCOPE
    )
  end

  def get_reporting
    request = build_request
    response = @client.batch_get_reports(request)
    response.reports.first.data
  end

  def build_request
    date_range = @analytics::DateRange.new(start_date: @start_date, end_date: @end_date)
    metric = @analytics::Metric.new(expression: @metric_type)
    dimension = @analytics::Dimension.new(name: @dimension_type)
    @analytics::GetReportsRequest.new(
      report_requests: [@analytics::ReportRequest.new(
        view_id: Rails.configuration.google_analytics_view_id,
        metrics: [metric],
        dimensions: [dimension],
        date_ranges: [date_range]
      )]
    )
  end
end

コード解説

# lib/google_analytics_reporting.rb
class GoogleAnalyticsReporting
  require 'google/apis/analyticsreporting_v4'
  SCOPE = ['https://www.googleapis.com/auth/analytics.readonly'].freeze
  def initialize(start_date, end_date, metric_type, dimension_type)
    @analytics = Google::Apis::AnalyticsreportingV4
    @client = @analytics::AnalyticsReportingService.new

まずクラスので必要な情報を定義していきます。

# lib/google_analytics_reporting.rb
    ENV['GOOGLE_PRIVATE_KEY'] = Rails.application.credentials.google_analytics[:private_key]
    ENV['GOOGLE_CLIENT_EMAIL'] = Rails.application.credentials.google_analytics[:client_email]
    ENV['GOOGLE_PROJECT_ID'] = Rails.application.credentials.google_analytics[:project_id]

は、認証のために必要な情報で、参考にしたqiitaにはjsonファイルで記述されていますが、環境変数に定義しても認証が行えるので 今回はこのように定義しました。 中身は、秘匿情報、環境ごとに取得したいのでcredentialsに記述しました。

# lib/google_analytics_reporting.rb
    @start_date = start_date
    @end_date = end_date
    @metric_type = metric_type
    @dimension_type = dimension_type

データの取得の期間、メトリックとディメンション(条件のようなもの)を引数で渡せるように定義しました。 将来、異なる情報を取得したいときにもこのクラスを使用できます。

# lib/google_analytics_reporting.rb
    @client.authorization = Google::Auth::ServiceAccountCredentials.make_creds(
      scope: SCOPE
    )
  end

initializeが呼び出されたときに認証を行なっています。

# lib/tasks/google_analytics.rake
    reporting = GoogleAnalyticsReporting.new(
      '2019-01-01',
      'today',
      'ga:uniquePageviews',
      'ga:pagePath',
    )

rake taskにてクラスをインスタンス化させます。 その際に、今回取得したいデータの条件を引数として渡してあげます。

# lib/tasks/google_analytics.rake
    reporting = reporting.get_reporting
    articles_pages = reporting.rows.select { |row| row.dimensions.first.match(%r{articles/.+}) }

get_reportingメソッドでGAからのデータを取得します。中身は、

# lib/google_analytics_reporting.rb
def get_reporting
    request = build_request
    response = @client.batch_get_reports(request)
    response.reports.first.data
  end
# lib/google_analytics_reporting.rb
  def build_request
    date_range = @analytics::DateRange.new(start_date: @start_date, end_date: @end_date)
    metric = @analytics::Metric.new(expression: @metric_type)
    dimension = @analytics::Dimension.new(name: @dimension_type)
    @analytics::GetReportsRequest.new(
      report_requests: [@analytics::ReportRequest.new(
        view_id: Rails.configuration.google_analytics_view_id,
        metrics: [metric],
        dimensions: [dimension],
        date_ranges: [date_range]
      )]
    )
  end

となっており、先ほど引数で渡した条件からデータを取得しています。 その際にview_idを渡していますが、これはconfig/environments/以下の環境ごとのファイルにそれぞれ定義しています。

# lib/tasks/google_analytics.rake
    articles = []
    Article.published.find_each do |article|
      article = article.attributes
      article['category'] = Article.categories[article['category']]
      article['public_status'] = Article.public_statuses[article['public_status']]

      articles_page = articles_pages.find { |articles_page| articles_page.dimensions.first.gsub("/articles/",  "") == article['uid'] }
      next if articles_page.nil?
      article['sessions_count'] = articles_page.metrics.first.values.first.to_i
      articles << article
    end

    if articles.present?
      Article.upsert_all(articles)
      Article.reindex
    end

ここで、dbに存在する。ブログ記事のデータを取得し、GAと同じuid(url)のもののsessions_countを更新させる処理を行なっています。 レコード数は少ないとは思いますが、大量にデータを扱っても良いようにfind_eachを使用しました。 https://blog.toshimaru.net/rails-find_each/

また、1件ずつsqlを発行するのは、処理的によくないのでbulk_insertのupsert_allを使いました。 最後に、reindexをしているのは、elastic searchを使用しているため、upsert_allして値を更新したらreindexをしないといけないからです。

最後に

APIを使用するのは初めてだったので、最初はqiitaの丸写しに近いものでしたが、コードレビューを行なってもらい、より自分の実装したいものになっていきました。 また、内容の理解やrubyの理解も深まりました。 同じ処理でも、よりパフォーマンスの良い処理、実は省くことのできる記述などがありました。例えばjsonファイルではなく必要な情報だけ環境変数に記述すれば良いところなど。

最初にqiitaからヒントを得るのは悪くないと思いますが、そこから

  • コピペしたものの中身はどうなっているのか
  • 何が必要なもので、何が不必要なのか
  • 削れる処理はないか
  • よりパフォーマンスをあげるには

をもう少し自分で考え、実装できるようにしないとなと思いました。