気ままに気ままのエンジニアブログ

定期的に得た知見を気ままに発信中

【Rails】任意のパラメータが入ったURLに画面遷移させるやり方

こんにちは。

夏がやっと来ました!さいクゥ〜

どうもハチマキです。

はじめに

画面遷移を実現するため、普段下記のように使っているlink_to。
これは至ってシンプルな画面遷移です。

・例1
= link_to 'yahooサイトへGO', 'http://www.yahoo.co.jp/', title: "yahooサイト", class: 'desc-center'

・例2
= link_to 'login_path', title: "ログイン", class: 'desc-center', target: '_blank' do
  ログイン
  %br
  画面
    
・例3
= link_to 'http://www.yahoo.co.jp/', title: "yahooサイト", class: 'desc-center' do
  = image_tag 'imgae/yahoo-logo'

今回ある検索結果を遷移先に定義したいと思ったのですが、やり方に迷いました。
そのため、色々調べた結果、新たな学びがあったので今回まとめていこうと思います。

環境

任意のパラメータが入ったURLに画面遷移させるやり方

早速ですが、まず初めにこちらから。こんな感じのURLに遷移させます。

https://〇〇/users?group_id=1?team_id=2

画面遷移の方法は、link_toのpathの引数にパラメータを定義することで実現できます。

*こんな感じ
= link_to users_path(group_id: 1, team_id: 2)

*こんな感じ
= link_to users_path(group_id: 1, team_id: 2), target: '_blank' do
   = image_tag 'imgae/yahoo-logo'

上記は至ってシンプルですが、「%5B%5D=〇〇」、「%3A」などが加わったURLに遷移させたい場合にどう定義するのか?となりました。
ここが+αで学べた点です!!

「%5B%5D=〇〇」、「%3A」⇦これらが何かというと、URLのエンコードでそれそれ記号などの意味を持ちます。

以下、URLエンコードの一例

  • ? → %3F
  • @ → %40
  • [ → %5B
  • ] → %5D

参考:TECHNICAL MANUAL

例えばこんなURLが生成されていたら?

https://〇〇/users?group_id%5B%5D=1&team_id%5B%5D=2

上記エンコードを参考に記述してみると、以下のような引数になります。

こんな感じ
= link_to users_path(group_id: [: 1], team_id: [: 2])

こんな感じ
= link_to users_path(group_id: [: 1], team_id: [: 2]), target: '_blank' do
 = image_tag 'imgae/yahoo-logo'

突然ですが、ここでもう一つ例を。

Q. 以下、パラメータを持つURLですが、どのようにlink_toを定義すれば、生成できるでしょうか。?

https://〇〇/?visit_date=2021-07-17&visit_time=19%3A00&expand_visit_minutes=60&num_guests=2

A. おそらくこんな感じじゃないかなと!(答えはわかりません..)

= link_to 〇〇_path(visit_date: '2021-07-17', visit_time: '19:00', expand_visit_minutes: '60', num_guests: '2')

まとめ

本日のポイントのまとめです。これらがわかってしまえば簡単なものです!

  • 任意のパラメータが入ったURLに画面遷移させるやり方は、pathの引数にパラメータを定義する!
  • %5B%5Dは、エンコードで変換されてるだけなので、調べればすぐ解決!怖くない!

以上、お疲れ様でした。

サイバー攻撃から身を守るWebアプリケーションのセキュリティーとは?

こんにちは。

最近やることが多く、サボりぎみでした...お久しぶりです。

どうもハチマキです。

はじめに

一定レベルの開発を早く出来るようにならねば...と突っ走っていたエンジニア当初。
だいぶ開発慣れしてきて、そろそろセキュリティーの勉強をしよう!と思い立った現在。

というわけで、今まで全然触れてこなかったセキュリティーに関して、これを機に色々調べながら知識習得を行っていこうというわけです。

今回は、サイバー攻撃の動向や種類、そして具体的な攻撃の影響や対策などについて、まとめていこうと思います。

目次

サイバー攻撃の動向

IPAが発表している「情報セキュリティ10大脅威」サイバー攻撃の被害数ランキングをみていきます。

2013年は、クライアントソフトウェアの脆弱性を突いた攻撃がランキング第1位、2014年には標的型メールを用いた組織へのスパイ・諜報(ちょうほう)活動、2015年にはインターネットバンキングやクレジットカード情報の不正利用が第1位でした。

2020年はというと、以下順位となっております。

・個人

1位:スマホ決済の不正利用
2位:フィッシングによる個人情報の詐取
3位:クレジットカード情報の不正利用

・法人

1位:標的型攻撃による機密情報の窃取
2位:内部不正による情報漏えい
3位:ビジネスメール詐欺による金銭被害

似たり寄ったりな気もしますが、上記のようにサイバー攻撃の順位は年々変動していることがわかります。これはサイバー攻撃の目的や攻撃手法の巧妙化が進むことが背景にあり、さらにセキュリティー上の脅威は、年々増大傾向にあります。

増大する背景には、テクノロジーの普及が関係し、テクノロジーの普及と相まって、サイバー攻撃は増大していくわけです。数あるサイバー攻撃を防ぐためには、セキュリティー脅威は知り、攻撃に適した対策を行うことが現代は必要不可欠であるということです。

情報セキュリティ10大脅威 2020:IPA 独立行政法人 情報処理推進機構

Webアプリケーションは何を守るべきなのか?

ここからが今回の本題とも言える「Webアプリケーションが守るべきセキュリティーとは何か」についてです。

私が購読した「プロになるためのWeb技術入門」には、Webアプリケーションを含む情報システムにおいて守るべき情報セキュリティは、以下3つであると述べられておりました。

1. 第三者への情報の流出を防ぐこと(機密性)

クレジットカード情報や顧客情報が第三者へ流出し悪用される(*最も問題になりやすいセキュリティリスク)

何が問題なのか?

  • 流出した情報の持ち主である顧客への被害
  • そのシステムを運用する企業にとっての信頼失墜
  • 会社の経営に大きな影響を与える可能性がある
2. 第三者による情報の改ざんを防ぐこと(完全性)

銀行口座残高やショッピングポイントの不正変更
三者の改ざんによって意図しない情報を発信させる
ウイルスなどを感染させる不正サイトに誘導させる

何が問題なのか?

  • 情報改ざんにより、本来の利用者やシステム運用する企業に不利益を与える
3. 適切な権限を持った人間が適切な情報を利用できること(可用性)

情報改ざんにより、サーバが不正に操作され、本来提供すべき情報やサービスを利用できなくなる

何が問題なのか?

  • 提供先が顧客であれば、社会的信頼の喪失や賠償問題
  • 自社システムであれば、システム利用ができず業務遂行が困難になる
見解

私自身が考えるWebアプリケーションは何を守るべきなのか?については、資産を守ることだと考えました。
情報セキュリティーリスクは、「脅威」が「脆弱性」を利用して資産を脅かすことから、やはり守るべきものは資産であると色々調べて至りました。

また別問題として挙げられていたことは、「何を守る必要があるのか = 資産」をそもそもわかっていないことが根本としてあるみたいです。ですので、まず「何を守るべきか」を洗い出し、資産とは何か?を定義することから始める必要があるなと感じました。

そして次のステップで、定義した資産を守るためにセキュリティー対策を考え、実際に投じていく必要がありますね。

サイバー攻撃とセキュリティー対策

セキュリティー対策には、「Webアプリケーションのセキュリティ対策」、「Webサーバのセキュリティ対策」、「ネットワークのセキュリティ対策」など、様々な問題に対する各種対策が存在しています。

その中で、いくつかサイバー攻撃をピックアップし、特徴や影響、対策などを、下記にまとめていきたいと思います。

■標的型攻撃

大枠の特徴は、「明確な目的を持って特定のターゲット(個人や組織)」を狙うサイバー攻撃です。攻撃対象への嫌がらせ、機密情報の盗み取り、金銭的利益などを目的としており、大きく3つの攻撃に分類されます。

1. 標的型攻撃メール

メールに「不正プログラムが組み込まれた添付ファイル」や「不正サイトへアクセスするためのリンク」を展開させ、対象端末を不正プログラムに感染させるサイバー攻撃です。

標的型攻撃と気づかず添付ファイルを実行してしまったり、リンクをクリックしてしまうと、端末がマルウェアに感染し、そこから被害が急速に広がります。

2. 水飲み場攻撃

ターゲットが日常的に閲覧するWebサイトを改ざんし、不正プログラムを仕掛けるサイバー攻撃です。

ターゲットにとっては、日常閲覧しているWebサイトのため、信頼性が高くあります。そのWebサイトを利用し、「組み込んだ不正プログラムにアクセスさせる」ことで、ユーザー端末にマルウェア感染や内部ネットワーク通信をされることにより、被害が広がっていきます。

3. 潜伏型と速攻型

標的型攻撃における内部攻撃です。
潜伏型は企業内のネットワークに長期間潜伏し、機密情報を搾取することを目的としたタイプの標的型攻撃で、一方速攻型は、数時間から一日程度で、情報を盗み出す攻撃を指します。

標的型攻撃の対策

万事未然に防ぐことは不可能に近いことを理解する必要があり、侵入を前提とした対策(侵入の早期発見・迅速な対応)が有効な対策となります。

入口対策


出口対策

  • ウイルス感染による外部への不審な通信を見つけて遮断する
  • ログを日常的に取得し、異常な通信を見つけるために定期的にチェックする
  • 万が一データが流出してしまっても、情報にアクセスできないようデータを暗号化しておく


内部対策

  • メールを受信する社員・従業員への教育
  • LANシステム側でヘッダや本文に注意を促す文言を挿入してから配送する

標的型攻撃への対策|情報管理担当者の情報セキュリティ対策|企業・組織の対策|国民のための情報セキュリティサイト
標的型攻撃とは?基本的な仕組みと対策方法 | DAiKO+PLUS(プラス)

脆弱性を突く攻撃

プログラムの不具合や設計上のミスが原因となって発生した情報セキュリティ上の欠陥を狙ったサイバー攻撃です。修正プログラムを提供するまでの間に、その脆弱性を狙ってきます。

バッファオーバーフロー

攻撃対象のコンピュータに許容量以上のデータを送りつけ、誤作動を起こさせるサイバー攻撃です。

原因

  • OSやアプリケーションの脆弱性(メモリ領域に本来想定している情報量以上の値が入力された結果、リターンアドレスなどの致命的な部分を上書きしてしまう)

影響

  • 本来想定している値よりもずっと大きな値を変数部分に入力することで、処理しきれなくなった情報を溢れさせ(オーバーフロー)、他のサイバー攻撃の踏台にされたり、乗っ取りが行ったりする

対策

  • ユーザ側
    • セキュリティソフトを最新にする
    • 修正パッチの導入
  • 開発者側 *ポイント:脆弱性を担保し、未然にオーバーフローを防ぐことが重要
    • コード記述時の対策
    • コードの静的検査
    • デバッグ

バッファオーバーフローとは?攻撃・対策方法とDoS攻撃との違いを解説|サイバーセキュリティ.com

クロスサイトスクリプティング

Webアプリケーションの脆弱性を利用して、悪意のあるデータを埋め込み、スクリプトを実行させるサイバー攻撃です。
動的サイト(例:TwitterなどのSNS掲示板等)に対して、自身が制作した不正なスクリプトを挿入することにより起こります。

原因

影響

対策

  • ユーザ側
    • 最新のブラウザにアップデートする
    • スクリプトの実行設定を無効化する
    • セキュリティソフトを導入し、不正なスクリプトをブロックする
  • 開発者側
    • エンドポイントへの総合的なセキュリティソフトの導入
    • 不正なサイトへの誘導と思われるメールをブロックする
    • ネットワーク内部から不正サイトへのアクセスをブロックする

クロスサイトスクリプティングとは?仕組みと事例から考える対策|サイバーセキュリティ.com

SQLインジェクション

アプリケーションの脆弱性を突き、本来意図しない不当なSQL文が実行(不正なプログラムが注入)されることで、データベースのデータを不正に操作するサイバー攻撃

原因

  • WEBアプリケーションが不正アクセスの意図があると知らず、外部から送信されたSQL文章を誤解してしまう

影響

  • データーベースに記録されている情報の流出(情報漏えい)
  • WEBサイトの改ざんによる多種多様な被害
  • システムへ不正ログインや乗っ取り

対策 *ポイント:脆弱性の原因を作らない実装

SQLインジェクションとは?種類・感染原因と対策を徹底解説|サイバーセキュリティ.com

不正アクセス

IDとパスワードの使いまわしが狙われるサイバー攻撃

パスワードリスト攻撃

あらかじめ入手し、リスト化したID・パスワードを利用して、正規ルート(利用者のアカウント)から不正アクセスを試みるサイバー攻撃

利用者は同じID・パスワードの組み合わせを複数のサイトで使用する傾向が強いため、パスワードリスト攻撃の成功率は高くなっている状況がある。

原因

  • 複数のサイトで同じパスワードを利用している
  • ユーザーのセキュリティリテラシーの低さ

影響

  • 該当アカウントを乗っ取り(本人になりかわって様々な行動が可能になる)

対策 *ポイント:ユーザー側の対策

  • 他社ログインパスワードを使いまわさない
  • 紙のメモを利用する
  • 電子ファイル(パスワード付き)
  • パスワード管理ソフトを利用する

パスワードリスト攻撃とは?被害の原因と対策方法|サイバーセキュリティ.com

ブルートフォース攻撃

ユーザのアカウント・パスワードを解読するため、考えられる全てのパターンを試す方法で、文字通り総当たりのサイバー攻撃

原因

  • 特にない

影響

  • 金銭的な被害
  • 個人情報などの情報が漏洩
  • Webサイト改ざん、SNSの不正利用

対策 *ポイント:解読不可能に近いパスワードを作成する

  • 8桁以上のパスワードを設定する
  • ログインロックを設定する
  • 2要素認証を設定する

ブルートフォースアタック(総当たり攻撃)とは?そのやり方・実際にかかる時間・対策方法は?|サイバーセキュリティ.com

DoS攻撃 / DDoS攻撃

複数に分散した攻撃用マシンから公開サーバーに一斉かつ意図的に負荷をかけ、サーバをダウンさせるサイバー攻撃
DoS攻撃:一つのパソコンから攻撃
DDoS攻撃:複数のコンピューターから一斉に攻撃

原因

  • 複数コンピューターから一斉に、公開サーバーへ意図的に負荷をかけられること

影響

  • ウェブサイトへのアクセスができない、ネットワークの遅延が起こる(サーバーやネットワーク機器などに対して大きな負荷がかかるため)
  • 対象とされた企業や組織では、金銭面だけでなく信用面でも大きなダメージを被る

対策

  • 攻撃元のIPアドレスを特定して、そのIPアドレスからのアクセスを遮断すること(*Dosに限る)
  • 海外からのアクセスを遮断する(アクセスを国内だけに絞る)
  • DDoS攻撃対策ツールの導入
  • 被害の拡大を防ぐネットワーク監視システムの導入

DDoS攻撃とは? 意味と読み方、対策方法 | NTTコミュニケーションズ 法人のお客さま

以上

最後に

今回は、サイバー攻撃についてまとめてみました。
私自身、直接サイバー攻撃に出くわしたことがありませんが、ふと短な所にサイバー攻撃は潜んでいることを今回知ることができました。

それとやはり世にアプリケーションを出している身からすると、セキュリティー面もしっかり考えられるエンジニアにならんといけないなと思った次第です。

まずは書籍から目を通して、知識習得を行なっていこうと思います。

【SQL向上ポイント】SQL力を上げるためには、構文理解じゃなくテーブル構成の理解を深めるべきだ!

こんにちは。

GWがあけました。悲しい...

どうもハチマキです。

はじめに

SQLを学び始めた当初、手も足も出ないSQLに課題を感じ、SQLチャレンジという名の毎月数個のクエリ作成を自分に課せ、組んだSQLにレビューして頂くという、先輩巻き込み企画を数ヶ月行なっておりました。

そのおかげもあり、今ではjoin, union allはもちろん、状況に応じてサブクエリを4つ組み合わせたSQLなども組めるようになり、数ヶ月前とは桁違いにSQL力が向上しました。

そこで感じたことは、SQLは構文(select, fromなど)を覚えれば組めると思っていたが、実はそうではないということ。
タイトルの通り、SQL力を上げるためには、むしろテーブル構成(どんなテーブルで、どのようなデータが管理されているのか)の理解が重要だということに気付きました。

今回の記事では、0からSQLを学習した私が、学びながら感じたSQL向上のポイントについて書いていきたいと思います。

*補足:既存アプリケーションでのデータ抽出を対象にしております

対象
  • データ抽出のやり方がいまいち分からない方
  • クエリの組み方のコツを知りたい方
  • SQLの学習を始めようとしている方
  • SQL構文の理解は進んできたけど、いまいち理解がまだふわっとしている方
環境
  • DB:MySQL
  • ツール:Sequel Pro(Mac用のMySQLのデータをGUI操作で管理するためのアプリケーション)
  • マシン:Mac
参考テーブル例
  • usersテーブル
    • id
    • email
    • name
    • created_at
  • postsテーブル
    • id
    • text
    • created_at
    • user_id

初級編:理解すべきSQL構文はこれで良い!

まず初期に理解すべきSQL構文はこれだけで良いという事です。以下を理解できれば、シンプルなデータ抽出のクエリは、問題なく組めるようになると思います。

  • SELECT:データ取得
    • COUNT関数:数を数える関数
    • SUM関数:合計値を求める関数
  • FROM:テーブル指定
  • INNER JOIN(内部結合):テーブル結合*外部結合との違いを理解しておく必要あり
  • OUTER JOIN(外部結合):テーブル結合*内部結合との違いを理解しておく必要あり
  • WHERE:条件指定
    • BETWEEN:範囲指定
    • AND:複数の条件指定
    • IN:複数要素の判定
    • =:単数要素の判定
    • IS NULL:NULLを判定
    • IS NOT NULL:NULL以外を判定
  • GROUP BY:データのグループ化
  • ORDER BY:データ並び替え
    • DESC・ASC:昇順・降順ソート

**重要ポイント
SQL構文のインプット学習だけは、ぜひやめて頂きたい!!
良くありがちなのは、SQLの書籍を購読するインプット学習です。しかし残念ながら、いざ手を動かすと何も身に付いていないことに驚愕する羽目になります(体験談です..)

0からSQLを学ぶ時こそ、Sequel Proなどのツールを活用して体感で学ぶ学習方法の選択をおすすめします。

中級編:初級編で実現出来ない場合に学ぶべきSQL構文

中級編では、少々複雑なデータ抽出であっても、以下を使いこなせれば、問題なくSQLを組めるようになることでしょう。

  • サブクエリ:クエリに含まれるクエリ
  • UNION / UNION ALL:結果の統合
  • CASE:条件分岐(データ分別)
  • その他
    • 関数/日付関数[比較, 加算, 差分, 抽出](time, TIMESTAMPDIFF, truncate, concat, group_concat , date_format, convert_tz, etc...)
    • 拡張機能(with rollup, etc...)

**重要ポイント
中級編を学び始めたということは、初級編の構文だけでは実現出来ないデータ抽出に出会したということです。

おそらくすでに思考は、初級編の構文だけでは実現出来なくないか?このクエリとこのクエリを組み合わせればデータ抽出できるかも?クエリとクエリの統合はどうやったら実現出来るんだ?などなど、様々な良い疑問を持つ思考になっていることでしょう。この疑問を持つことが初級から中級にステップアップする上で、非常に重要なポイントだと私は感じました。

SQL向上のポイント

今回の本題は、ここからです。
上記、初級編/中級編の構文が理解出来たからといって、SQLが組めるようになるかと言うと、実はそうでもありません。
あくまでこれまでは、構文を理解しただけだからです。SQLを組めるようになるためには、構文理解以外に構文の使い方をマスターする必要があります。(なので、体感で学習する必要があるのです)

先に述べますが、重要なことは、要件のキーワードからクエリを組み立てられる力を身につけることです。

そのためには、要件(抽出したいデータ)を自然言語からSQL構文への変換作業を身につける必要があります。

以下ステップでは、SQLを組む上での手順について書いていきます。
私の場合、SQLを組む際は、一度頭の中で構成を考え、クエリを組むようにしています。頭の中での組み立て、そこからどのようにしてアウトプットを出しているのかを言語化していきたいと思います。

▼ステップ1:アプリケーションのDB構造を理解する

アプリケーションのDBファイルを確認し、ざっくりアプリケーション全体のDB構造の理解を深めましょう。
ポイントは、どんなテーブル構成で、カラムにはどのようなデータが管理されているのかを全体的に掴むことです。

*ここまで出来るとベスト!
抽出したいデータを構成しているテーブル構成・カラムを特定できると、このあとの手順をスムーズに進めることが出来るかと思います。

▼ステップ2:要件を整理し、明確にする

要件あるあるは、様々な要素が混在していて、結局どのようなデータを抽出すべきかがわからないことが、多々あります。
SQLを組む際は、SQL構文を考える前に、まず抽出要件を整理し、明確にしましょう。

例)以下、明確にした要件
・要件:直近1年間で、TODOリストを投稿したユーザデータ一覧

▼ステップ3:要件をキーワードごとに分解する

明確にした要件をキーワードごとに分解する作業です。ここで重要なことは、分解したキーワードのテーブル構成を把握することです。

上記例を参考にすると、「直近1年間」「TODOリストを投稿した」「ユーザ」のように分解できます。

直近1年間で、TODOリストを投稿したユーザデータ一覧」

*キーワード分解は、アプリケーションのテーブル構成に左右されますが、あくまでここでは考え方が重要です。

▼ステップ4:自然言語でアウトプットを明確にする

次にやるべきことは、自然言語でアウトプットを明確にすることです。もう少し具体的に言うと、ステップ1で得たDB構成、テーブル構成の理解をベースに、抽出したいカラム(SELECT文)のあらいだしをここで行っていきます。

例)以下、自然言語で明確にしたアウトプット
・SELECT
 ・id
 ・氏名
 ・メールアドレス
 ・投稿日
 ・etc..

▼ステップ5:from句に定義するテーブルを決める

ここでのポイントは、ステップ4であらいだした最終アウトプットのデータが何かを考え、どのテーブルをfrom句に定義すべきかを決めることです。

例を参考にすると、

直近1年間で、TODOリストを投稿したユーザデータ一覧

最終的なアウトプットは、ユーザデータ一覧です。そのため、from句にはusersテーブルを定義します。

・SELECT
 ・id
 ・氏名
 ・メールアドレス
 ・投稿日
 ・etc..
・FROM users

*複数クエリを結合する(サブクエリ)際も考え方は同様

▼ステップ6:要件を自然言語からSQL構文へ変換する

ここから実際にクエリを作成する作業に入ります。

**重要ポイント
ステップ1で理解を深めたDB構造(テーブル構成やカラム)が非常に役立ちます。
基本的にデータ抽出する際は、1テーブルだけで済むことはほとんどありません。いくつかのテーブルを結合し、要件に合わせたテーブルを作っていく必要があります。
ステップ1でDB構成を掴めていないと、要件に合わせたテーブルを作ることは不可能に近いと思います。

例を参考にSQL構文への変換作業です。

直近1年間で、TODOリストを投稿したユーザデータ一覧

  • 直近1年間
    • WHERE、BETWEENを用いて、created_atカラムの範囲を指定する
  • TODOリストを投稿したユーザ
    • from句に定義したusersテーブルに、外部キーを用いてpostsテーブルをjoinする(*要件では、未投稿ユーザは対象外にする必要があるため、join(内部結合)を使用します)
  • ユーザデータ一覧
    • GROUP BYを用いて、user.idでグループ化する
    • ORDER BYを用いて、post.created_atに並び替える

上記例を参考に組んだSQLです。

SELECT
 users.id
 users.name
 users.email
 posts. created_at
FROM users
JOIN posts on users.id = posts.user_id
WHERE posts.created_at BETWEEN '2020-01-01 00:00:00' and '2021-01-01 00:00:00'
GROUP BY user.id
ORDER BY post.created_at;

*今回の例は、非常にシンプルなデータ構造のため簡単ですが、現場では要件で分解したキーワードが複数テーブルから成り立っていることが多々あるため、fromで定義したテーブルに複数テーブルを結合する必要が出てきます。

*複雑なSQLの場合、クエリごとに抽出したいデータが取得出来ているかを確認しながら進めていくと良いかと思います。

最後に

これでSQL向上ポンイトは以上になります。

この思考が正しいのかは、正直わかりません。あくまでこの思考になったことで、個人的にはクエリが整理され、理解が進んだことでSQLを組みやすくなったということです。

改めて重要だと感じたことは、やはりテーブル構成の理解を深めることかと思います。この理解が進まないと、構文を理解出来たからといってSQLを組めるようにはならないからです。

ただ、構文を覚えないとSQLは組めないので、結局はどっちも重要なのかもしれません。

今回はSQL力を向上させるための一つの手段として得た学びを記事にしてみました。
ぜひご参考になれば幸いです。

ちなみにSQLは非常におもろいです。

                                            • -

日々勉強です。
以上、ハチマキでした。

1年前に投稿した「公開コードレビュー会に参加してみての感想」を、1年後の自分がレビューしてみた

こんにちは。

不意にブログ名を変更してみました。

どうもハチマキです。

はじめに

今から1年ちょっと前に、未経験からエンジニアに転職致しました。当時はよく初学者向けの勉強会に参加して、そこで得た学びを記事に書いていました。

現在エンジニアになって約1年半、前提知識や経験は、当時から考え難いくらい成長してきたなと我ながら感じております。

この1年でどのようなことを感じるようになって、どのような視点を持つようになったのか、自分自身の成長加減が気になったこともあり、当時書いた勉強会の記事をベースにあたかもコードレビューかのように、コメントを加えていきながら振り返りを行ってみたいと思います。

▼この記事の内容にレビューを加えていきます
hachimaki37.hatenablog.com

対象

  • 実際エンジニア歴1年ってどんな感じなのかを知りたい
  • プログラミング挫折しそうな人
  • エンジニア成り立てってどんな感じなのかを知りたい

環境

当時参加した勉強会の概要

  • レビュー会概要
    • ポートフォリオレビュー者(3名)に対して、一人30分程度で現役エンジニアの方が公開レビューしていく
    • レビュー会のみ参加者:15名ほど(私はこちらで参加)
    • 平均年齢:おそらく20代中盤
  • 3名のポートフォリオ一覧(個人アプリケーション)
    • 1人目:昆虫食専門のサイト
    • 2人目:一人旅行で現地で遊んでくれる人を探すような掲示板サイト
    • 3人目:本のアウトプットアプリ

では、早速いきましょう!

総論に対するコメント

1番の学びポイントは、自身のマインド面に変化をもたらした。
同じような駆け出しエンジニアの人たちであろう、自身の作成したサービス(ポートフォリオ)に素直に驚かされた。

と同時に、レビューされる人はもちろん、レビュー会のみ参加している方々の温度感、熱量に焦りすら感じた。
自身を見直し、改めて計画して頑張ろってなった。

今振り返っても、この勉強会で得たマインドの変化は、良い緊張感と良い焦りを与えてくれた機会でした。

発表していたポートフォリオは、今思えばシンプルな作りではあるが、当時の自分には恐ろしいほどのレベルの差を感じました。
そこから得た学びで、目標や計画に落とすようになり、実行に移せたからこそ今の自分があるように感じます。
LGTM👍

テーブル名やカラム名、メソッド名の一つ一つに意図した意味をしっかり持たせながら設計していくことの重要性を学んだ。
ちゃんと一つ一つに開発者の意味がこめられていることを知らなかった。

メソッド名から変数名など、一つ一つの意図を考えながら実装していく必要があります。
意図した意味というよりも、そのコードを見た他者が迷いなく、意図を理解できるような設計にすることが重要です。

*保守のしやすさ(仕様理解や開発効率)に直結するため

学んだことに対するコメント

・レビューする側の視点を知れたこと
 ・現在、レビューしていただく側のため、レビューする側の観点や流れをざっくり知ることができた

・具体的に
 ・メソッド名 / テーブル名 / カラム名は、意図した(相手へのメッセージ)名称の定義を行なっているか
 ・テーブル名、カラム名が、UI画面と紐づくように意図して定義されているか
 ・コードに処理の意図を感じ取れるか
 ・コードは、シンプルにわかりやすく書かれているか

プログラムの可読性や開発効率を上げるための重要な観点だと感じます。
今はまだレビューして頂く側ではあるが、コードレビューのコメントで上記箇所は、良し悪しに関わらず必ずコメントを頂いているように感じます。

メソッド名 / テーブル名 / カラム名は、意図した(相手へのメッセージ)名称の定義を行なっているか

上記にも追記しましたが、保守性などに起因する重要なポイントです。

テーブル名、カラム名が、UI画面と紐づくように意図して定義されているか

どのようなデータを格納するためのカラムなのかを考えた上で、命名する必要があります。チーム内でも命名に関して相談をする機会が多々あります。

コードに処理の意図を感じ取れるか

自分にしか理解できないコード(スパゲティコード)になっていないかは重要な観点です。
スパゲティコードになることで、保守性が下がる。つまり開発効率が下がることに直結する点ですので、気をつける必要があります。

例) 
#バッドコード
@users = User.find(1) 

#グッドコード
@user = User.find(1)

#バッドコードの理由:ユーザidを取得しているのに、変数名が複数形になっている

コードは、シンプルにわかりやすく書かれているか

可読性を上げるために、不要(余計)なコードは書かないこと、コード短縮できる箇所は、短縮したコードを書くこと。

例)
#バッドコード
user = User.find(1)
user.id = 10
user.save

#グッドコード
user = User.find(1)
user.update(id: 10)

#バッドコードの理由:短縮できるコードは、リファクタリングしましょう。

・レビューする時のfile確認の流れ
 ・README(github) → schema → routes → models → controllers → ・・・

レビュー観点という面では、アプリケーションの全体像(README(github) → schema..)から具体(controllers →..)に確認を進めていくことで、スムーズなレビューにつながるように感じました。(まだレビュアーではありませんが・・)

各fileの確認ポイントに対するコメント

アプリケーション概要を把握するためのREADMEに詳しく書く
概要
技術ポイント
機能一覧
環境 / 技術構成
インフラ構成
テーブル設計
etc...
 ※インフラ構成や、テーブル設計を記載する際は、図で表現するとイメージがついて良い

アプリケーションの概要を理解するために、READMEを詳しく書いておくことは良い点かと思います。
READMEを見ることで、他社がアプリの全体像を掴めること=スムーズなコードレビューに繋がる要素かと思います。

schemaに対するコメント

migration file内に、null: falseを書く癖をつける

データの整合性を保つために必要です。null: falseを指定したカラムは、空の状態でDB保存できなくなるため、例えば、フォームの氏名を必須にした時に、null: falseを定義しないと、氏名は未記入のままDBに保存されてしまいます(データが不整合になる)

すると、思わぬバグになったりするので、必要な箇所にはnull: falseを追加するようにしましょう。

テーブル内で重複するデータを禁止するために、unique: trueを書く

unique: trueは、重複レコードを1つにまとめるためのメソッドです。
例えば、userモデルのemailカラムに、a@gmail.com、b@gamil.com、a@gmail.comのメールアドレスがあった場合、a@gmail.comの重複データをまとめてくれます。

定義する場合は、下記のようにindexにuniqueを貼る必要があります。

~~省略
add_index  :users, [:email], unique: true

*補足

  • uniqueメソッド:Rails5以降で非推奨
  • distinctメソッド:Rails5以降で正式メソッド

Rails 一意性制約のかけ方|Nori|note
Railsでreferencesを使用した外部キーに、同時にUnique属性を設定する - TechBox

命名に不可算名詞を使うことは、良し

理解に戸惑う可能性があるなら、出来るだけ不可算名詞は避けた方が良い。
不可算名詞の場合、rails g modelを実行した時にrails側で識別できず、余計なsやesがついてしまう恐れがあります。(config/initializers/inlrections.rbをいじれば問題は解消できる)
Railsの命名規則【単数形・複数形】 - 箱のプログラミング日記。

テーブルの紐付けは、リレーションシップをうまく使い分ける

テーブル同士の関連付けを、各モデルに定義(belongs_to、has_many)する事で、直感的なコードでデータ取得が可能になります。

#user.rb 
belongs_to :user

#schedule_result.rb
has_many :schedule_results

#レコード取得する時
% user.last.schedule_results
% schedule_results.last.user

【Rails】アソシエーションを図解形式で徹底的に理解しよう! | Pikawaka - ピカ1わかりやすいプログラミング用語サイト

DBのテーブル名、カラム名をユーザー行動から考えて作成する

ユーザ操作に関連した、DB設計が重要です(ユーザ操作と全く違うデータを管理するのはナンセンスです)
また命名規則がいくつかあるため、確認しながら進めていきましょう。
Railsにおける命名規則 - Qiita
データベースオブジェクトの命名規約 - Qiita

テーブル数を意識して、作成する

テーブル数よりも、1テーブルあたりのカラム数を意識したほうが良いです。
とあるデータでは、1テーブルが持つべきカラム数は、10以下が妥当とのこと。10カラムを超える設計であれば、正規化できないか一度見直す必要があります。
先人達から学ぶRailsのテーブル設計 - Qiita

routesに対するコメント

ユーザーにわかりやすく、意図したURL設計をしていく

ユーザにわかりやすくというよりも、何に対して (URL)/処理内容に適した (HTTP Method)URL設計にすることが重要です。
*覚えやすく、どんな機能を持つURLなのかがわかるようにする
リソースの一部更新におけるURL設計 - Qiita
RESTful APIのURI設計(エンドポイント設計) - Qiita

resourcesメソッドを使ったroutes設定

RESTの原則に則って構築しましょう。resourcesを定義することで、railsですでに定義されている7つのアクションのHTTPメソッドを活用したroutes設定ができます。

*GET, POST, PUT, PATCH, DELETE → index, new, show, create, update, destoryアクションに対応
resources | Railsドキュメント
【Rails】resourcesメソッドを使ってルーティングを定義しよ | Pikawaka - ピカ1わかりやすいプログラミング用語サイト

member routesを活用する → 初学者の場合、get / postのみで書いてしまうことがある

上記で書いた7つのアクション以外にもアクションを定義したい時に有効です。memberは、特定のデータ(users/:id/likesのように:idが入るアクション)に対するアクションを定義することができます。
railsのroutes.rbのmemberとcollectionの違いをわかりやすく解説してみた。〜rails初心者から中級者へ〜 - Qiita

URLに動詞を入れない(規約で決められている)

動詞ではなく、名詞を活用すること。
*動詞を使用することで、変数や関連を使う場合に不自然な命名になってしまうため
モデルやメソッドに名前を付けるときは英語の品詞に気をつけよう - Qiita

単数形リソースを使った方がわかりやすくなります。

idが不要な場合は、単数形リソース(resource)を活用した方が、シンプルでわかりやすくなる
*例えば、/profile/:idのようなパスを、/profileで割り当てることができます。
Rails のルーティング - Railsガイド

ホワイトリスト形式とブラックリスト形式の使い分け

形式を分けることによるセキュリティ対策です。

  • ホワイトリスト形式
    • 「安全な対象」を定義したリストです。リストで定義されているアプリケーションだけを実行させ、リストに定義されていないアプリケーションは実行できません。安全なものだけを利用し、それ以外はすべてブロックするために存在するリストです。
  • ブラックリスト形式
    • 警戒する必要がある「危険な対象」を定義したリストです。リストに定義されているアプリケーションは実行させません。使用してはいけない危険なアプリケーションやプログラムを定義し、危険だと分かっているものを利用しないために存在するリストです。

ホワイトリスト式セキュリティの仕組みとは?ブラックリストとの違い | DAiKO+PLUS(プラス)
ホワイトリスト方式セキュリティの仕組みと効果:株式会社 日立ソリューションズ・クリエイト

shallowオプションでroutesを整える

長くなるURL問題を解消してくれるオプションで、最小限の情報でリソースを一意に指定できるルーティングを作成できます。
ただ、デメリットもありそうなため、使用する際には、改めてよく調べてから使いましょう。
Railsのroutesのshallowは安易に使わないで欲しい – Matsubo Tech Blog
uRails のルーティング - Railsガイド

modelsに対するコメント

最大文字数が必要な箇所には、バリデーション(lengthオプション)を定義してあげる

ユーザビリティを高める一つの手段として、良いかと思います。文字数に制限を設けることで、最小文字数や最大文字数を設定することができます。
例えば、最大文字数を超えている場合や最小文字数に達しない場合にエラーを表示する事で、ユーザアクションの迷いが軽減されます。

#user.rb
validates :name, length: { maximum: 10, message: '氏名は10文字以下に設定して下さい' }

バリデーション例外を捕捉する "!"を加える

エラー原因の調査に役立ちます。
「!」の有無の違いは、保存出来なかった場合の振る舞いに違いがあります。
エラー内容を知りたい場合は「!」を追記し、例外を発生させる事でその内容に応じたエラー文を表示させましょう。

例)

if @user.save
# 保存が正常に完了すれば「true」、保存できない場合「false」を返します。

if @user.save!
# 保存が正常に完了すれば「true」、保存できない場合、例外ActiveRecord::RecordInvalidが発生します。

rails save! create! update!のバリデーション例外を捕捉する - Qiita

他のユーザーが編集不可能にするために、current_userと紐づける

current_userを使用することで、サインインしているユーザーを取得することができます。
例えば、current_userに紐付けず実装した場合、他のユーザが編集や削除などが出来てしまいます。そのため、current_userを用いてセキュアなアプリケーション構築を心がけましょう。

Active Modelを使用し、簡潔に書いていく

多くのモジュールを含むライブラリを用いることで、シンプルかつ簡単に実装が可能になります。
Active Model の基礎 - Railsガイド

複雑な処理は、controllersに記述していくのではなく、modelsにメソッドを用いて記述する

ロジックをControllerに記載することも可能ですが、ファットコントローラーになり、コード管理がしづらい状態になります。
そもそものControllerの役割は、ViewとModelを繋ぐ(ユーザーからの要求を処理し、モデルやビューと連携を行なう)ことです。データの表示はViewに、ロジックの実行はModelに切り分け、MVCアーキテクチャーをうまく活用した実装にしましょう。
【Rails】MVCフレームワークを初心者向けに丁寧に解説! | Pikawaka - ピカ1わかりやすいプログラミング用語サイト

スコープを積極的に使用し、意味のあるまとまりを作る

Active Recordの機能の一部で、モデルにscopeを定義することにより、複数のクエリを一つのメソッドにまとめることができます。
コントローラーで複数のクエリを書くよりもscopeを使えば、コードがスッキリする。

例)

scope :active, -> { where(is_active: true) }
default_scope  -> { user(name: "DESC") }

Railsのモデルのscopeを理解しよう - Qiita

has_manyを使って、追加されるメソッドを使う
アソシエーションを貼ることで、使えるメソッドが複数ある

has_manyを定義することで、class_name、source、foreign_keyなどのオプションが使えるようになるため、うまく活用しながら効率的に実装を進めていきましょう。
railsアソシエーションオプションのメモ - Qiita
has_many | Railsドキュメント
【Rails】Associationメソッドまとめ - Qiita

findとfind_byの使用を明確にする

  • find
    • idの値が分かっていて、そのidのデータを取得したい場合に使用する

*各モデルのidを検索キーとしてデータを取得するメソッド
*id以外の条件で検索不可

例)

User.find(1) 
  • find_by
    • idの値が不明で、id以外のカラムを検索条件としたい場合に使用する

*各モデルをid以外の条件で検索するメソッド(idでも検索可能)
*複数の検索条件を指定可能
*返ってくる結果は、最初にヒットした1件のみ

例)

User.find_by_email('test@gmail.com') 

find、find_by、whereの違い - Qiita

該当するレコードがあれば取得、無ければ作成してくれるfind_or_create_byメソッド

引数の条件に該当するレコードがあればそれを返し、もしなければ新規作成するメソッドです。

例)

User.find_or_create_by_name('テストベッカム')

controllerに対するコメント

controllersでの処理はシンプルに記述する
modelsに処理を切り分ける

上記同様のコメントを参照。
ロジックをControllerに記載することも可能ですが、ファットコントローラーになることで、コード管理がしづらい状態になるため、ロジックはmodelsに切り分けて書くようにしましょう。

最後に

これでレビューは以上になります。

当日は、〇〇は〇〇だ!というように、あまり細かな疑問を持つことはなかったように感じます。前提知識が徐々に積み上がってきたことで、このコードはこうした方がより良いのでは?などの疑問や考えが出てきたように思います。

まだまだ技術面はジュニアですが、スキル向上に向けて、引き続きコツコツと努力していきたいと思います。

*実は今回の記事レビューを思い立った理由は、チェリー本(Ruby)を読んだアウトプットでした。
ただ以前書いた記事の内容は、railsがメインだったなぁと思ったので、改めて別のアウトプットを考えてみようと思います。

                                            • -

日々勉強です。
以上、ハチマキでした。

【Git】使用中の作業ブランチに最新のmasterファイルをmergeするやり方

こんにちは。

エンジニア成り立てに読んでいた書籍をまた読み返すと、新たな気づきがあり嬉しい。

どうもハチマキです。

はじめに

git関連で知っておくべきことをテーマに、今回書いていきたいと思います。

今回のテーマは、使用中の作業ブランチに最新のmasterファイルをmergeするやり方です。
チーム開発をしていると、様々なシーンで多々行うことがあります。
やり方をわかっていれば簡単に解消できますが、初めて出くわすとなかなか大変なものです。

そのため、コマンド手順と合わせまして、自然言語の説明も書いていきたいと思います。

環境

事象

チームの方から最新のmasterブランチを作業ブランチにmergeしてもらって、検証環境にUPして欲しいという依頼がきた。

*つまりやることは、使用している作業ブランチを最新にするということです。

対応方法

*補足

  • 作業ブランチは、test_fileとします。
  • 作業ブランチに修正ファイルがある場合、事前に下記どちらかを実行してください
    • コミットはせずに変更を退避したい場合:git stashを実行
    • 編集ファイルが不要の場合:git checkout .を実行

git: git stashの使い方 - Qiita
git reset & git checkout 使い分けまとめ | DevelopersIO

▼言葉で表した手順です。

  1. 作業ブランチからmasterブランチに切り替える
  2. ローカル環境のmasterブランチを最新にする
  3. masterブランチから作業ブランチに切り替える
  4. 作業ブランチに最新のmasterブランチをmergeする
  5. mergeされたファイルを作業ブランチにpushする

*下記のようにGithubにMerge branch 'master' into test_fileがpushされていれば完了です。
f:id:hachimaki37:20210426142512p:plain

▼続いて、実行コマンドに変換した手順です。

1.  $ git checkout master
2.  $ git pull origin master
  remote:~~~~
  , done.

3.  $ git checkout test_file
4.  $ git merge master
5.  $ git push origin test_file

*下記のようにGithubにMerge branch 'master' into test_fileがpushされていれば完了です。
f:id:hachimaki37:20210426142512p:plain

以上です。お疲れ様でした。

                                            • -

日々勉強です。
以上、ハチマキでした。

【15分でざっくり理解を深める】つまり何なんだ!?歴史から考えるオブジェクト指向

こんにちは。

最近勉強会が再開されるようになって嬉しい。

どうもハチマキです。

はじめに

ちゃんと理解を深めていなかったオブジェクト指向。最近やっと1人称で開発ができるようになってきて、開発している中で様々な疑問(Why)が出るようになってきました。
例えば、

  • コードの可読性を上げるには、どういう記述にするのが良いのか?
  • なぜこういう処理、コード記述をする必要があるのか?
  • 記述メソッドにはどういう意味があるのか?適切なのか?
  • このコードだと、パフォーマンスはどうなるのか?

などなど、過去を振り返ると「プログラムが呪文に見える → プログラム理解はあまりできてないけど、なんとなくこんな処理が行われている → このプログラムは、〇〇処理を行なっている」と段階を踏んで理解が進んできました。

現在Railsをメインに開発を行なっており、疑問の中の一つにオブジェクト指向って結局何なんだ?どう活用していけば、より良いプログラムになるんだろうか?こんな疑問をふと持つようになりました。

今回はこの疑問に応えるべく、オブジェクト指向についてなるべく理解(自分の口で喋れるようになる)を上げるため、言葉を噛み砕いて書いてみました。

おそらく15分程度で読める内容になっているかと思います!(内容に誤りがありましたら申し訳ございません)

対象

*コードを踏まえた説明はしておりません。

目次

オブジェクト指向とは?オブジェクト指向言語とは?

まずは、Wikipedia先生に伺いましょう。

オブジェクト指向とは、ソフトウェア開発とコンピュータプログラミングのために用いられる考え方である。
元々は特定のプログラミングパラダイムを説明するために考案された言葉だった。明確な用語としては1970年代に誕生し、1980年代前半に知名度を得て、考案者の手を離れた自由で曖昧な定義のまま発展を続けた後に、1990年代に入るとソフトウェア工学の様々な分野にも応用されるようになった。ソフトウェア開発における一つの標語のような扱い方もされている。

ふむふむ。
つまりプログラミングの考え方や記述方法の枠組み(プログラミングパラダイムであるということですね。

次にオブジェクト指向言語とは何か?について、またWikipedia先生に伺います。

オブジェクト指向プログラミングとは、互いに密接な関連性を持つデータ(変数またはプロパティ)とコード(関数またはメソッド)をひとつにまとめてオブジェクトとし、それぞれ異なる性質と役割を持たせたオブジェクトの様々な定義と、それらオブジェクトを相互に作用させる様々なプロセスの設定を通して、プログラム全体を構築するソフトウェア開発手法である。

何言ってんだ?関連データと処理をまとめた集まり?オブジェクト?
早速何がなんだか理解できません。

オブジェクト指向言語について様々調べていると、

  • オブジェクト=モノ
  • 互いに関連するデータの集合とそれらに対する手続き群をひとまとめにしたオブジェクト

などの説明が多く見受けられました。正直なんとなくわかったようなわからんようなです。
もう少し理解を深めるため、少し歴史から順を追っていきました。

*今回様々調べて得た解は、オブジェクト指向言語とは、関連する情報(データ)の集まりと挙動をひとまとめにした「モノの集まり」だということです。

プログラミング言語の歴史

プログラミング言語の歴史は、1930年ごろに遡ります。(意外と最近にびっくりしました)

f:id:hachimaki37:20210410111552j:plain
f:id:hachimaki37:20210410111600j:plain

プログラミングの歴史は1900年代〜と、思っていた以上に歴史が浅い。にも関わらず進化のスピードは早いことを調べてる中で感じました。

オブジェクト指向自体の誕生は、1970年前後に生まれ、最初に提唱したのは、計算機科学者アラン・ケイ氏と言われております。1972年から開発公開を始めたSmalltalkの言語設計を説明する中でオブジェクト指向は発信され、1981年頃から知名度を得た概念です。

そして知名度を得た背景には、コンピュータの急激な進歩によって、より複雑なソフトウェアが求められ始めたこと(時代)が大きく関連しています。
それが、次に説明するソフトウェア危機というものです。簡単にどんなものなのか書いていきます。

ソフトウェア危機とは?

そもそもソフトウェア危機とは、ソフトウェア工学がまだ十分に確立していなかった頃、よく使われた言葉です。

▼詳しくはこちらから
ソフトウェア危機 - Wikipedia

端的にいうと、ソフトウェアの発展が、利用者(市場)の求める需要を満たすだけの生産量・品質・費用・時間の面で追いつかず、供給できないという問題や課題を指します。

それら問題により、具体的に開発プロジェクトでは下記のような実態が顕著に現れていました。

Wikipedia先生の引用

・予算を超過してしまったプロジェクト
・予定期間を超過してしまったプロジェクト
・品質の低いソフトウェア
・要求仕様を満たさないソフトウェア
・管理不能状態のプロジェクトと、保守困難となったコード

オブジェクト指向の成り立ち

ソフトウェア危機が叫ばれた背景には、プログラムの複雑化とバグ問題が密に関わっています。

これはつまりコンピュータの性能が向上したことで、従来より大規模なソフトウェアが書かれることになり、プログラムの複雑化やプログラム保守が難航(追加や修正がより困難)する問題へと発展しました。(プログラムは複雑化する一方なのに、管理手法もなければ、データ型は基本的な数値でしかなかったわけです)

これら問題を解決するために目指したことは、「開発効率の向上」「メンテナンス性の向上」です。

上記を目指す上で、様々な手法や方法論が開発される中考えられたのが、プログラムの独立性、再利用性、拡張性の3つを追求するということです。

そして、その3つの性質を兼ね備えた概念こそ、オブジェクト指向なのです。(継承・カプセル化ポリモーフィズム

やっとつながってきました。

オブジェクト指向の本質(2021-05-14追記)

オブジェクト指向の本質は、いかにコード間の依存関係を減らし(疎結合),メンテナンスしやすいプログラムを書くかです。

そのためには、コードをある程度の固まりとしてグループ化を行い、コードの依存関係を排除する。つまり「粗結合」を意識しながらコード間の依存関係を最小に保つように心がける必要があります。

*なぜメンテナンスしやすいプログラムを書く必要があるのか?(密結合ではダメなの?)
結論は、生産効率を上げるため。だと私は認識しております。
機能ごとの独立性が高い事で、あるコードを変更しても(別コードへの)副作用を与えることがなくなるからです。

密結合(コード間の依存関係が高い)の場合、手もつけられないぐらい複雑に絡み合ったコードの固まりができてしまう。つまり数行のコードを追加・変更するだけでさまざまな副作用を考慮しなければいけなくなり,生産効率が極端に下がりはじめます。(あるコードを変更すると、他のコードで別の問題が発生するなど)

以下(継承は、疎結合と矛盾する面あり)は、これらを実現させるための手段と私は認識しています。
第4回 オブジェクト指向の本質:Software is Beautiful|gihyo.jp … 技術評論社

オブジェクト指向の価値

では次に、オブジェクト指向の最大の価値は何かについてです。

早速結論ですが、それは「抽象化による、わかりやすさと利便性」にあります。

んーよくわからんですね。。なので、いきなりですが一例あげたいと思います。
我々の自然言語の世界では、例えばボール(Ball)を見ると、これはボールだ!と認識できます。
そして同様にリンゴ(Apple)を見れば、これはリンゴだ!と認識できるはずです。

プログラムの世界では、そうはいきません。ボールを見てもボールとは認識出来ませんし、リンゴを見ても同様に認識が出来ません。

では、どうするのか?
ボールは、転がる・跳る・丸い・皮膜や外殻に包まれている、リンゴは、赤い・丸い・甘い・食べるのように、関連する情報(データ)と挙動をひとまとめにしたモノ(オブジェクト)に名前をつけることで、ボールはボールになり、リンゴはリンゴになり、そして認識できるようになります。

我々の自然言語の世界では、ボールやリンゴは、すでに情報が抽象化されたモノの名前を使って、それらを認識し活用しています。
日常会話の中で、転がる・跳る・丸い・皮膜や外殻に包まれているのを買いに行くんだよね!というより、ボールを買いに行くと言った方が自然でわかりやすいですよね?

つまりこれが抽象化であり、このプログラミングパラダイム(概念)がオブジェクト指向です。

ただ抽象化だけでは、価値を実現させることができません。
次に説明する継承、カプセル化ポリモーフィズム多態性の3大要素をうまく活用する(組み合わせる)ことが重要です。

▼組み合わせることで、下記のようなメリットをもたらすことができます。

  • システムの柔軟性が増す
    • カスタマイズがしやすくなる
  • スムーズな作業につながる
    • 開発者同士での認識の共有がしやすくなる
  • 開発作業の効率化を図れる
    • 再利用がしやすい

*デメリット

  • オブジェクト指向の概念を習得・理解することに時間がかかる
    • 理解に時間がかかることで、作業進捗に影響が出がち
  • オブジェクト指向の概念の理解度が、人によって差が出ることがある
    • 理解度のバラツキが作業の停滞を生む
  • 一から開発する場合、コードが複雑になりやすい

オブジェクト指向の3大要素

1つ目:継承

Wikipedia先生から引用

継承(けいしょう、英: inheritance、インヘリタンス)とはオブジェクト指向を構成する概念の一つである。あるオブジェクトが他のオブジェクトの特性を引き継ぐ場合、両者の間に「継承関係」があると言われる。

主にクラスベースのオブジェクト指向言語で、既存クラスの機能、構造を共有する新たなクラス(派生クラス、派生型)を定義すること(subclassing、サブクラス化)ができる。またそのような派生クラスは「親クラス(スーパークラス)を継承した」という。具体的には変数定義(フィールド)や操作(メソッド)などが引き継がれる。またJavaC#などのインタフェース実装のように、機能セットの仕様(プロトコル)のみを引き継ぐ場合もある。

一般的に、BがAを継承する場合、"B is a A."(BはAの一種である)という意味的な関係(Is-a関係)が成り立つ。従って、同じふるまいを持つからと言って、意味的に無関係なクラス間に継承関係を持たせるのは適切でない場合が多い。

継承は、再利用の仕組みです。

継承を利用することで、親クラスを継承した新しいクラス(派生クラス)は、メッセージ・メソッド・属性といった親クラスの構造を受け継ぐことができます。つまり、派生クラスでは、親クラスの構造を再利用でき、新たに機能を実装することが可能になるということです。

もう少しわかりやすく、ボールを例に説明していきます。
例えば、サッカーボールを作る時、一からボールの情報を定義する。テニスボールを作る時もまた同様、一からボールの情報を定義する。これ結構めんどくさくないですか?
できればすでにあるボールという概念(情報)にサッカーボール特有の情報を加えるだけで、サッカーボールにできた方が良くないですか?

プログラムの世界でも同様です。
サッカーボールとテニスボールの抽象度をあげると、どちらもボールです。定義したボールの情報を継承すると、ボールに関連する情報や挙動を再利用することが出来ます。
つまりサッカーボールを作りたければ、継承したボールの情報に黒と白の色の情報、大きさの情報などを加えるだけで、サッカーボールにすることができるのです。

このボールに関連する情報や挙動を使うことこそ、再利用の仕組みであり、継承なのです。

▼メリット

  • コードの追加・修正といったメンテナンスが容易になる
  • より抽象的な共通する機能を親クラスにまとめることができる
  • コードが読みやすくなる(可読性が上がる)

*継承を利用する上で重要なことは、クラス同士の関係が派生クラス is a 親クラス(派生クラスは親クラスの一種である)という意味的な関係(Is-a関係)を築く必要があります。
*今回の例だと、サッカーボール is a ボール(サッカーボールはボールの一種である)という関係です。

逆転の発想でオブジェクト指向の「継承」を使いこなす | IT × マーケティング コラム
【オブジェクト指向】クラスの継承とは?【プログラミング】 | 初心者向け完全無料プログラミング入門
【第3回】継承 (1/4):CodeZine(コードジン)

2つ目:カプセル化

Wikipedia先生から引用

カプセル化(カプセルか、英: encapsulation)とは、データ(属性)とメソッド(手続き)を一つのオブジェクトにまとめ、その内容を隠蔽することを言う。

カプセル化は、一つのオブジェクトとしての独立性を高める仕組みです。

カプセル化を利用することで、データのアクセスを制限(不整合を引き起こすような操作をできなくする)し、データを保護することで、オブジェクトの安全性を高めることができます。

データアクセスの可否はアクセス指定子(private/public)と呼ばれるものによって決められ、クラスやオブジェクト外からのデータアクセスに制限(拒否)をかけることができます。

つまり!先ほどの例を使うと、サッカーボールの情報を勝手に、色を白と緑に、大きさを拳くらいに変えられたら困りませんか?
これサッカーボールなのに、なんかテニスボールみたいになってるやん!ってなりますよね。。(情報が壊れる)

これが一つのオブジェクト(サッカーボール)としての独立性を高める仕組みであり、カプセル化なのです。

▼メリット

  • 仮に異常なデータ変更が来た場合は、適切な値に戻したり、変更を拒否することができる
  • 予期せぬバグを防止できる
  • 情報を直接操作することをできなくし、情報が壊れてしまうことを防止できる

カプセル化とはなにか?超わかりやすく解説します! | じゃぱざむ
オブジェクト志向のカプセル化を、総合医療病院で例えると「窓口」という説を語ってみる。 | IT × マーケティング コラム

3つ目:ポリモーフィズム多態性

Wikipedia先生から引用

ポリモーフィズム(英: Polymorphism)とは、プログラミング言語の型システムの性質を表すもので、プログラミング言語の各要素(定数、変数、式、オブジェクト、関数、メソッドなど)についてそれらが複数の型に属することを許すという性質を指す。ポリモルフィズム多態性、多相性、多様性とも呼ばれる。対義語はモノモーフィズム (Monomorphism)、単態性、単相性で、プログラミング言語の各要素が唯一つの型に属するという性質を指す。

ポリモーフィズムは、拡張性の仕組みです。

異なる型のオブジェクトを同一視し、そのオブジェクトの型によって動作を切り替えることが可能になります。
もう少し細かくいうと、物事を抽象概念として捉え、一つの命令に対し、各々が持った別の動き(振る舞い)を可能にします。

例でいうと、ボール・サッカーボール・テニスボールってどれも跳ね方が異なります。この「跳ねる」という挙動を、サッカーボールとテニスボールに合わせて、別々の跳ね方に書き換える(オーバーライド)と、その跳ね方に変えてくれます。(呼び出し先に応じて、適切なメソッドが実行されることで、良しなに振る舞いが変化する)

つまり跳ねるという挙動(同じメソッド名)でも、ボール・サッカーボール・テニスボール(オブジェクト)の変化に応じて、結果が変わることはポリモーフィズムの拡張性の仕組みなのです。

▼メリット

  • 何度も同じコードを書く必要がなくなるため、コードがきれいになる
  • プログラムの読みやすさが向上する
  • プログラムの再利用のしやすさが増す

【オブジェクト指向とは何ぞや】ポリモーフィズムとダックタイピングを理解しよう | shin>>media
ポリモーフィズム(多相性)とは - IT用語辞典 e-Words
プログラマー1年生がポリモーフィズムについて学んだのでRPGで説明する。 - Qiita

まとめ

以上で、一通りオブジェクト指向の説明が終わりました。いかがだったでしょうか。

様々調べて得た私の解は、オブジェクト指向言語とは、関連する情報(データ)の集まりと挙動をひとまとめにした「モノの集まり」だということです。
そしてオブジェクト指向言語において特に重要なことは、継承・カプセル化ポリモーフィズムをうまく組み合わせるということです。

今回を通して、オブジェクト指向の理解は、だいぶ進んだように思います。
ただあくまで、オブジェクトを使ったプログラム全体を構築する手法であるということ、そして概念だけを理解したからといって、実際のプログラムに実装できるかはまた別問題だというです。

なので、次は実践に活かせるようオブジェクト指向設計実践ガイドを読んでみようと思います。

参考資料

                                            • -

日々勉強です。
以上、ハチマキでした。

【Git/GitHub/エラー解消法】git pushしたらConflicting filesが発生した時の解消方法

こんにちは。

いつでもLGTMは嬉しい。

どうもハチマキです。

はじめに

今となっては問題なく解消できるようになったコンフリクト。
エンジニア成り立ての時は、コンフリクトが発生した時点で重い腰をあげるように解消に挑んだものです。

今回は、発生したコンフリクトの発生原因とその解決法について書いていこうと思います。

環境

問題

作業ブランチで進めていた開発作業が完了し、いざGithubにgit pushしたら一部のファイルでコンフリクト(競合)が発生した。。
f:id:hachimaki37:20210413194138p:plain

コンフリクトってなに?発生原因は??

端的にいうとコンフリクトは、ファイル同士の競合です。
https://wa3.i-3-i.info/word11329.html

コンフリクトの発生原因は、同じもの(ファイルやコード)を同じタイミングで使う(修正や追加)ことにより、整合性がとれなくなることで発生します。

例えば、AさんがTODO登録機能を開発するために、最新のmasterファイルをgit pullして、作業ブランチを作成します。

一方Bさんは、TODO更新機能を作成するため、Aさんと同様の手順を踏んで、作業ブランチを作成し、開発を進めています。

1週間後、Aさんは開発が完了し、ファイルZをgithubにpushして作業ブランチをmasterファイルにmergeします。(*現時点で最新のmasterファイルが更新されました)
その2日後、Bさんも進めていた開発が完了したため、修正したファイルZとファイルYの2つのファイルをgithubにpushします。

おそらくここで、今回テーマであるコンフリクトが発生するはずです。

Aさんの編集ファイルZが、masterブランチにmergeされたことで、Bさんが現在作業ブランチで使用しているファイルZとの整合性(Aさんが編集したファイルZの情報がない)が取れないことが理由でコンフリクトが発生します。

*補足
開発現場では、時よりコンフリクトが発生します(僕は何度も出くわしました)
理由はご察しの通り、複数人で開発を進めているためです。そのため、上記例にあげたことが常に起こっているため、タイミングよく、同ファイルを修正し、誰かがmasterファイルにmergeすると、今回のように整合性が取れずコンフリクトが発生するのです。

ただ、解消方法自体は、至って簡単ですので、順を追って解消していきましょう!

解消方法

*作業ブランチは、test_fileとします。
github上でコンフリクトしたファイルを確認しておく(下の方にファイルパスがあるはず)とコンフリクトファイルが事前に把握できます。

▼言葉で表した手順です。

  1. 作業ブランチからmasterブランチに切り替える
  2. ローカル環境のmasterブランチを最新にする
  3. masterブランチから作業ブランチに切り替える
  4. 作業ブランチに最新のmasterブランチをmergeする(mergeすると、ターミナルやファイル内で競合したファイルパス、コードの箇所を教えてくれると思います)
  5. conflictが発生した箇所(コード)を修正する
  6. 編集ファイルをgit addする
  7. 編集ファイルをgit commitする
  8. 編集ファイルをgit pushする

以上です。

▼続いて、実行コマンドに変換した手順です。

1.  $ git checkout master
2.  $ git pull origin master
3.  $ git checkout test_file
4.  $ git merge master
Auto-merging ファイルパス
CONFLICT (content): Merge conflict in ファイルパス
...
Automatic merge failed; fix conflicts and then commit the result.

# 補足
# $ git stateでファイルを一度確認

5. conflictが発生した箇所(コード)を修正する
6.  $ git add test_file
7.  $ git commit -m 'fix Conflicting files'
8.  $ git push origin test_file

以上です。

これで、コンフリクトは解消できるはずです。
コンフリクトが発生すると、最初はなかなか焦りますが、一旦深呼吸して実行できれば意外とすんなり解消できるものです。