稲枝の押入れ

いなえが適当なことを書いては、しまっておく場所

git初心者によるgit入門

前置き

対象

この記事は、「gitって何?」もしくは「名前だけ聞いたことはあるんだけど何となく手を出さないままでよく知らない」という人を主な対象としています。「コマンド普段から打つわけじゃないから抵抗がある or 面倒だ」という人にも向けています。また、僕自身の備忘録も兼ねています。あしからず。(おそらくこれらのユーザーの殆どはWindowsを使っているだろうという邪推から特に断りなくOSはWindowsを使っているものとして話を進めていきます)

目標

これを読んで、とりあえず最低限の機能については使える、知識としてではなく使えるくらいにはgitをわかってもらえたらなと思います。

注意

gitは一般には(というか原則は)CUI(文字だけの黒画面でコマンド打ち込んだり)で操作をするものなのですが、周りの人を見ていると、gitを使うことに抵抗を覚えている人がメインとしてGUIを使っている人(僕もその1人ですが)が多いので、SourceTreeというGUIフリーソフトを使ってとりあえずgitの便利さを知ってもらい、かつ難しい事をしている訳ではないという事を知ってもらうつもりでいます。コマンドをカタカタ打ってgitを使いたい!という方は沢山ドキュメントが転がっていますので適当なワードで検索することをおすすめします。とはいえ、SourceTreeについての説明部分以外についてはCUIで使う人にとっても有用な部分があるかもしれないので軽く見ていってください。

また、この記事では本当の本当に基本的な事を扱います。あくまでもgitに対するよくわからないという意識を拭うことのみを目的としています。

加えて、筆者も初心者なので、記述が正確であるかはわかりません。他のサイトと記述が矛盾している場合、自らでどちらが正しいか判断してください。そのような場合など、こちらにコメント等頂けると筆者も勉強になるばかりでなく、記述がより正確になるのでありがたいです。

本題

gitとは?

gitとは何か、と聞かれて一言で答えると「分散型バージョン管理システムの一つ」と僕ならば答えるのですが、人によっては何のことやら?という感じだと思います。順をおってみてみましょう。

バージョン管理システムの説明

バージョン管理システム」とは、そのまま「バージョン管理をするシステム」のことだろうというのは推測できるかと思いますが、ではその「バージョン管理」とは何でしょう?ゲームなどで(特にオンラインゲームで見る気がしますが)、「ver.1.2」みたいな表記を見ることが有りますよね。あれがバージョンだということは大体の人は知っていると思います。バージョン管理システムとはまさにあのバージョンを管理するシステムなのです。さて、バージョンはこれでわかったと思いますが、バージョン管理とはなんでしょうか。

それではここで、普段見るゲームのバージョンというものを、遊ぶ側からではなく作る側として考えながらバージョン管理とは何かを見ていきましょう。

例えば、

  • ゲームの基本システムが完成したものをver.1.0
  • 「モンスターA」を追加してモンスターの数を増やしたものをver.1.1
  • 「ボスA」を足したものをver.1.2
  • 「モンスターB」を追加してモンスターの数を増やしたものをver.1.3

としましょう。その上でこれをゲームを作る、開発者目線から見てみます。ver.1.2ではボスを追加しましたが、ボスの動きの実装が難しく、バグが出てしまったとします。バグが取り除ければそれに越したことは無いのですが、バグがなくプレイできる様なバージョンを用意して置かないと、ちょっとプレイして確認したいところがある、などといった時にバグのあるバージョンしかプレイが出来ずデバッグ的な観点からも不都合です。

ではどうすればいいかというと、それぞれのバージョンの状態でプロジェクトを何処かにコピーしてバックアップしておく方法が考えられます。そうすれば仮に最新バージョンでバグが出たとしても、ひとつ前のバージョンのバックアップがあるのでプレイ自体は問題なく行えます。こういったバージョン毎の管理がバージョン管理です。 しかし、多くの方がお気づきでしょうがこのような手動のバージョン管理は無駄が多いです。例えば

  • 新しいバージョンが完成する度に手動コピーをするので特にプロジェクトの規模が大きくなると時間がかかる
  • 同じく、プロジェクトの規模を増すほどに容量を食う
  • コピーした後、「ゲームver.1.0」「ゲームver1.1」とプロジェクトフォルダの名前を手動で書き換えないといけない
  • バージョンはわかってもそのバージョンでどのような変更がなされたか等はフォルダ名に書くわけには行かないので別途テキストを用意して管理しないといけない
  • モンスターAとモンスターBだけを実装したバージョン、つまりバグのあるボスAの実装を全て消したバージョンを作るのに手動でやるしか無い
  • 下のようにリネームの際の表記がブレてしまうこともあり、一貫性がなくなる

f:id:makiofinae:20170818164303p:plain

という感じです。欲を出すともう少しデメリットを出していけるのですが、ここではこれくらいにします。

ではどうすればいいのか、というところでバージョン管理システムの登場です。バージョン管理システムでは、上記のような手動のバージョン管理によるミスを防げる上に、より無駄のない管理が出来るようになっています。 例えばgitではフォルダをコピーしてバックアップしなくても、コミットという動作をすれば、バージョンを作ってくれる上に、その日時や変更内容、コメントなどの情報をまとめたものを作って管理してくれます

バージョン管理システムのイメージ

と、ここまで説明しましたが、イメージがつかめない人がいるかもしれません。その人はゲーム等のセーブをイメージしてくれればいいと思います。バージョン管理システムとは、開発(先程はゲーム開発の例を出しましたがそれ以外のソフトウェア開発についても)等をする際に、その開発内容のセーブやロード等を出来るように管理してくれるシステムなのです。 ゲームでの「あのアイテム取りそこねて先に進めないからあそこのセーブデータに戻ってアイテムを取り直そう」というのと同じように、開発でも「新しく実装したものがバグが有って取るのが難しいから前のバージョンに戻ってもう一度コードを書きなおしてみよう」というのを出来るようにするのがバージョン管理システムです。

gitの大まかなイメージ

「分散型バージョン管理システム」のうち、残りの「分散型」について説明をする前に、gitの簡単なイメージを掴んでおきましょう。 gitでは、ユーザーは「リポジトリ」というバージョン管理の情報等を入れる入れ物の様な物をつくり、そこに新しいバージョンについての情報を追加したり、そこにある過去のバージョンの情報を参照したりすることでバージョン管理をします。つまり、自分のPCの中には実際に開発中である様々なファイル(ソースコードやデータ等)とリポジトリがあり、開発中の様々なファイルの変更をセーブしたい時は、ローカルのリポジトリに対して、バージョンを保存してくれと言ったような命令を出して現状の情報を保存するわけですね。 また、gitではサーバ上などオンラインにリポジトリを作ることも出来、ここに自分のローカルのリポジトリの内容を反映させたり、逆にサーバ上のリポジトリの内容をローカルのリポジトリに反映させたりすることも出来ます。これを用いると、多人数開発等で非常に便利で、これこそがgitの便利な所ではあるのですが、ここについて詳しく書くのはこの記事の趣旨に沿わない上に、僕もそれほど詳しくないのでこの記事では書きません。もし機会があれば別の記事に起こしたいですね。気になる人はGitHub等について調べるといいかもしれません。

「分散型」の意味

ここではそれほど重要なことではないのですが、gitは「分散型バージョン管理システム」だと言ったので分散型の部分も説明しておこうと思います。どうでもいい人はここは読み飛ばしてもらって構いません。 まずそもそも、バージョン管理システムには、分散型でないもの、つまり集中型というものがあります。集中型バージョン管理システムとは、リポジトリはサーバーに1つであり、そこで直接バージョン管理をする、というシステムです。つまり、新しいバージョンが出来た時に、自分のPCにあるローカルなリポジトリにその情報を追加するのではなく、サーバ上のリポジトリに直接追加します。 これに対してgitでは、説明してきたとおりバージョン情報の追加は自分のPCにあるローカルなリポジトリに対して行います。サーバ上のリポジトリには、ローカルなリポジトリの内容を一部若しくは全部反映するという形でバージョン情報を追加したりするので、サーバ上のリポジトリに全てのバージョン情報があるわけではないという状態になります。このような管理の仕方をするものを分散型バージョン管理システムと言います。

gitの基本的な知識

はじめに

GUIで使えるようになろうといっても流石にgitの事がわかっていないのにツールの話ばかりしてもわかるようにはならないので、まずはgitの基本的な事について話そうと思います。ただし、恐らく使いながら慣れたほうが良いと思うので、それなりに細かく書くつもりではいますが、イメージさえ掴めたらここで全てを理解しようとせず次に進んで構いません。 ここではGUIを想定しているので、コマンドという言い方よりも機能という言い方を採用します。

repository(リポジトリ)

先程軽く説明して、ここまでの説明でも使ってきましたが、念の為確認しておきましょう。リポジトリとはバージョン管理情報を入れておく入れ物の事です。もう少し具体的に言うと、ソースやファイルの状態について、保持しておくファイル(群)の事を指します。gitではまず最初にこの入れ物を作ってから、そこにデータを追加していったりする形でバージョン管理を行っていきます。

commit(コミット)

一番よく使うことになるであろう機能がこのコミットです。何をする機能かというと、ゲームで言うとセーブをする機能です。つまりはリポジトリにコードの変更について保存します。

どうやって管理してるの?

gitはセーブをしたり出来るといって、commitについて先程書きましたが、gitはその時のソースコード等の情報を保存しているのではありません。commitによって保存されるのは、commit時の情報ではなく、前回までのcommitから導かれる前回のソースコードと、現在のソースコードとの差分です。 ゲームに例えてみましょう。RPGポーションを初めから3つ持っているとして、その状態でまずセーブがされているとします。そのあと、ポーションの数が4つになったとして、そこでセーブします。ゲーム等であれば大体「ポーションの数が4つである」というのを元のセーブデータに上書き保存する形でセーブすると思います。 しかし、gitでは「ポーションの数が1つ増えた」という情報をコミットすることになります。これによって

という情報から辿っていって現在のポーションの数を4つだ、と認識するわけですね。これをソースコードでもやるわけです。例えば

#include <stdio.h>
int main() {
     printf("Hello World\n");
     return 0;
}

というデータが既にcommit等を済ませた状態であるとして、

#include <stdio.h>
int main() {
     printf("Good Night World\n");
     return 0;
}

と書き換えた場合、commitをすると、リポジトリにはこのコードが保存されるのではなく、 「3行目の『 printf(“Hello World\n”);』が『 printf(“Good Night World\n”);』に書き換えられた」 という情報がリポジトリに保存されるわけです。(厳密に言うと「書き換えられた」と言うのは違う気がしますが、ここでは分かりやすさを優先します)

これを繰り返していってバージョンを管理する訳なので、gitは変更情報(差分)を連ねて保持してくれるシステムとも捉えることが出来ます。

branch(ブランチ)

ブランチというのは、ゲームで例えるとセーブスロットと考えると良いかもしれません。もしくは、世界線と考えると少しわかりやすいかも知れないですね。gitは変更情報を連ねて保持してくれるシステムとさっき言いましたが、このブランチというのはその連なりの分岐を作る機能なのです。ただ、ここで注意しておかなければならないのは、ブランチは分岐を作成・管理するのに使われるものの、ブランチそのものは直接分岐を作成するというよりも、commitの連なりやその分岐の中で現在どこにいるかというのを示す機能でもあるという事です。 ゲームの例で見てみましょう。世にいうギャルゲー、つまり恋愛シミュレーションゲームを考えます。あの手のゲームは所謂攻略対象としてヒロインが設定されているのですが、1周のプレイでは誰か1人を攻略することになると思います(自分はギャルゲーに詳しくはないので、本当にそうなのか!?と詰め寄られると困りますが、ここではそう考えます)。例えば、クリスマスに誰をデートに誘うか、というベタベタの選択肢があったとしてAさんとBさんがその候補にあがったとしましょう。この場合、素直にやるのであれば、まずAさんを誘って攻略を進めた後、また最初からやり直してBさんを攻略します。しかし、このクリスマスイベントまでは同じ手順を辿るのであれば、わざわざ二度も行うのは面倒ですよね。そこで考えられるのが、セーブです。セーブスロット1ではAさんを誘って、セーブスロット2ではBさんを誘う、そして最後には、セーブスロット1ではAさんを、セーブスロット2ではBさんを攻略します。 さて、プログラミングの話に戻りましょう。ソフトウェアの開発では、複数のメンバーが同時に機能の追加や、バグ修正を行ったりすることがあります。また、複数のリリースバージョンが存在し、そのそれぞれを保守しなければならないといったこともあります。こういった場合に役に立つのがブランチです。上記のセーブスロットの例の様に、例えばブランチ「bug_fix」ではバグの修正を、ブランチ「add_enemy」では敵の追加を、と言った風に、依存性の無い機能をそれぞれ平行に管理することが可能になります。この機能のメリットは、次に紹介するmerge(マージ)を含めての部分が多いのですが、そうでなくとも、ブランチについた名前から、そのブランチに属するcommit達が何をする為にされたものなのかを推測する事ができるという利点があります。とある機能についてのコードしか書かない、と決めていたら良いのですが、バグに気付いたら修正したくなるものですよね。かといって敵の実装の一部→バグ修正→敵の実装の一部という風にコミットされているとあとで見直す時に見にくくなってしまいます。しかしブランチを分けて置くことによって、いつでも当該部分についてcommitをすることができるようになるのです。

merge(マージ)

mergeというのは、分岐を再び統合する処理です。gitはその時のコードではなく変更についての情報を保持しているとさっき言いました。そして、その変更情報の連なったものは、分岐してbranch等を通して意味のあるかたまりとして捉えることができました(例えばバグ修正、など)。つまりは、元の情報に変更情報を1つずつ適用していけば、現在の情報が導ける訳です。となると、とある所で分岐したブランチについて、その元は同じであるがゆえに、ある変更情報の連なりに、別の変更情報の連なりを反映する、といったことも可能になります。このようにして、一度分岐した変更のかたまりを、再度統合する処理がmergeです。(以下、便宜上変更情報の連なりをブランチと表現します) しかし、このmergeはいつでもうまくいくとは限りません。あるブランチに別のブランチをマージしようとしたとき、それぞれの変更内容が矛盾してしまった場合、gitはそのどちらを採用すれば良いのかわからないのです。これをconflict(コンフリクト/衝突)と言います。コンフリクトが起きた場合は、その矛盾を解消してやらなければなりません。 具体的にどの様な時にコンフリクトするのでしょう。例えば、

#include <stdio.h>
int main() {
     printf("Hello World\n");
     return 0;
}

というコードに対して、ブランチ「night」では

#include <stdio.h>
int main() {
     printf("Good Night World\n");
     return 0;
}

と、3行目を書き換えてcommitしているのに対して、ブランチ「leave」では

#include <stdio.h>
int main() {
     printf("See You World\n");
     return 0;
}

と3行目を書き換えている事を考えましょう。 この時、3行目について、それぞれのブランチでは「 printf(“Good Night World\n”);」と「 printf(“See You World\n”);」という変更がなされています。この状態でどちらかのブランチにもう一方を統合することを考えてみたらどうでしょう。gitは3行目をどちらにすればいいかわかりませんね。ここでコンフリクトが生じます。 では、「wanna_know_name」というブランチがあって

#include <stdio.h>
int main() {
     printf("Hello World\n");
     printf("What's your name?\n");
     return 0;
}

こういった風になっているとします。元のHello Worldと比較すると、変更分は3行目と4行目の間に「 printf(“What’s your name?\n”);」が追加されたになります。これを「night」ブランチにマージしたらどうなるでしょうか? この場合変更分は、

  • 3行目と4行目の間に「 printf(“What’s your name?\n”);」を追加
  • 「 printf(“Good Night World\n”);」を追加

の2つなので、矛盾することなく、マージ後のコードは

#include <stdio.h>
int main() {
     printf("Good Night World\n");
     printf("What's your name?\n");
     return 0;
}

になります。

checkout(チェックアウト)

コミットは変更の積み重ね、ブランチは変更について分岐したもの、というのは話しましたが、となると今自分がどこに居るのでしょう?「そりゃ最新のコミットでしょ」と思うかもしれませんが、ブランチがいくつもあったら?また、今までゲームで例えた場合のセーブについて話してきましたが、ロードはどうするのでしょう?あのブランチの最新のコミットの状態をロードしたい、となったらどうすれば良いのでしょうか。 それはともかく、gitは差分で情報を保持するといいました。となると、常に現在の最新コミットがどこで、その最新コミットに比べた差分を見るわけです。この最新コミットがどこにあるかというのは何を基準に見て居るのでしょうか。 この二つの問いに対する答えはcheckout(チェックアウト)という機能を見ることで見えてきます。 チェックアウトとは、現在の作業ブランチを変更する機能です。またゲームの喩えをすると、選択しているセーブスロットを変更する機能になります。もっというと、別のセーブスロットをロードする機能、になります。 ブランチAからブランチBに移る場合「ブランチBにチェックアウトする」といいます。「ブランチAからチェックアウトする」といいたくなりますが、こうは言わない様です。

導入

実践

gitを使うメリットと、基本的な機能などについては何となく掴んでもらえたと思うので、そろそろその使う準備をしようかと思います。まず、この記事においては上記の通りGUIでgitを使えるようになる事を目的としているので、そのツールの紹介からしましょう

SourceTree

使うツールはこちら、SourceTreeです。もしかしたらもっと良いツールがあるのかもしれませんが、僕が教えてもらって非常に簡単に使うことが出来るようになったという事や、使い続けてきて充分使えるレベルのソフトウェアだという事を僕がわかっているのでこちらのツールを使っていこうと思います。

インストール

こちらのサイトからSourceTreeをダウンロード、インストールしてください。基本的に無料で使えると思うのでその辺は心配しなくて良いと思います。インストールする際等にアカウントを作ることを求められるかもしれません。もし将来オンラインでソースコードを管理することを考えているのであればGitHubのアカウントを取得してそれを登録しておいても良いかもしれません。(この記事ではSourceTree Version 1.9.13.7を前提として話を進めます)

不親切

色々ともしかすると選択肢等が出てくるかと思いますが、その辺は読めばだいたいわかると思うのでがんばってください…

リポジトリの作成

gitを使うにはリポジトリをまず作る必要がありますのでリポジトリを作ってみましょう。とはいっても難しいことはありません。左上の「新規/クローンを作成する」をクリックします。するとウィンドウ内に小窓が開くので、そのタブの中で「リポジトリを作成」を押し、「保存先のパス」にプロジェクトのパスを指定して「作成」を押します。これでリポジトリが作れました。

コミットしてみる

さて、次はコミットです。本当はgitにはaddという機能があって、gitで管理するファイルをこのコマンドで追加するのですが、Sourcetreeでは、これを自動で認識してくれるので、何も考えずコミットをすれば良いです。 コミットの仕方も簡単で、上の「コミット」ボタンを押して、コミット画面を開きます。変更点があるファイルが下側に表示されるので、コミットしたいものを選んで「Stage selected」を押すか、「Stage All」を押して、変更をステージします。変更をステージする、とは、変更を今回のコミットに含むと言うことを意味します。変更をステージできたら、下のメッセージボックスにコミットに関するコメントを書いて、右下のボタンを押すか、ctrl+Enterを押すだけでコミットは終了です。

ブランチを切る

ブランチを切る、とはブランチを作ることです。ブランチを作る、つまり新しい世界線・セーブスロットを作るのさえ、難しいことではありません。上にある「ブランチ」ボタンを押して、出てきた小窓に新しいブランチの名前を入力し、決定ボタンを押すだけです。

マージする

マージをしたい場合にも、またも上にあるマージボタンを押すのですが、この時に少し注意があります。それは、統合したい先のブランチにチェックアウトした状態でマージを押す必要があるということです。統合元ではないのです。 つまり、ブランチAにブランチBの変更を適用する(統合する=マージする)場合、ブランチAにチェックアウトした上でマージボタンを押す必要があります。 マージボタンを押すと、マージするコミットを選ぶよう言われます。マージしたいブランチの最新コミットを選択して右下の決定を押せば、自動でマージが行われます。 コンフリクトが発生した場合はダイアログが開くので、説明に従いながら衝突を解決してください。

現在のブランチを指定したコミットに移動させる

もう大体話したのですが、たまに便利なのを紹介しておくと、ブランチの現在位置を変更する機能があります。後から「うまくいかない原因を比較検証するためにあの状態からこの機能を実装してみたい」と言った時に過去のコミットに戻れる機能になります。これもいわばゲームでいうロードに近いですね。 やり方は、戻りたい先のコミットを指定して右クリックから「現在のブランチをこのコミットまでリセット」を選択するだけです。選択すると「Mixed」「Hard」など、どの設定で移動するかを聞かれますが、大体Mixedで問題ないでしょう。こいつらがなにかというと、ブランチの現在のコミットに合わせて、コードの方も変更するかという選択肢です。 オンラインリポジトリを使うようになるとこいつのせいで変に整合性が取れなくなることもあるので注意して使いましょう。

gitignore

地味に大事なのがこのgitignoreです。何かというと、変更を検知しないファイルをリスト形式で定義できるものになります。 例えば、コンパイルするたびに生成される.exeファイルや、VisualStudioを使っているのであれば、ソリューションについて更新があるたびに変更される.slnファイル等、定期的に変更が入り、かつ別にそれをコミットしたくはないというオブジェクトがあったりすると思います。これを検知せず、つまりはコミットの対象から外す様に設定できるのがgitignoreです。実際にはこれはgitignore.txt(ここでは名前が違うかもしれませんが気にしないでください)を編集することで行います。どこからそのgitignore.txtを開けるのかというと、まずSourceTreeのウィンドウメニューのツール->オプションを選択してオプションウィンドウを開きます。ここでGitのタブを選択し、「グローバル無視リスト」とある行の一番右の「ファイルの編集」をクリックすることで開けます。これは名前の通り全体に効果のある無視リストになります。ローカル環境でのみ無視するには.git/info/excludeを編集するという手がありますが、これは入門の範囲で扱う必要はないと思うので、必要であれば調べてみてください。
さて、gitignoreの中にどうやって更新を無視するファイルを定義するかですが例えばこのように行います。

#ignore thumbnails created by windows
Thumbs.db
#Ignore files build by Visual Studio
*.obj
*.exe
*.pdb
*.user
*.aps
*.pch
*.vspscc
*_i.c
*_p.c
*.ncb
*.suo
*.tlb
*.tlh
*.bak
*.cache
*.ilk
*.log
*.dll
*.lib
*.sbr

簡単に書くと

  • #で始まる行はコメント
  • *.[拡張子]の場合、その拡張子のファイルすべてが無視される
  • 特定のフォルダ以下を無視したい場合は"folder_name/"

という感じです。

詳しくはこことかここあたりを参考にするか、「gitignore 書き方」とかでググれば出てくると思います。

総括

gitについて

さて、グダグダな説明になってしまいましたが、みなさんgitのイメージは掴めたでしょうか。もし、この有用性にまでイメージを膨らませることが出来たのであれば、あなたは今日からでもgitを使うべきでしょう。 gitにはここで紹介していない機能や、その本領を発揮するオンラインリポジトリについて等、まだまだ強い機能が沢山あります。それらについて皆さんの興味をひくことが出来たなら幸いです。

その他ページ

gitの学習をするにあたって、役に立ちそうなページを紹介しておきます

  • サルでもわかるGit入門
    有名どころ。なんだかんだ忘れた時にみるのはここな気がする。一通り書いてある気がするのでここを見てやるのは普通にアリ。

  • LearnGitBranching
    めっちゃ便利なサイト実戦形式でブラウザ上でコマンドを打ちながらgitについて学べる。CUIも気になる人には特におすすめ

  • こわくないGit
    スライドでGitの原理等から色んな機能に触れてくれる。非常に分かりやすい。スライドなのでとっかかりやすい。

  • チーム開発に必要なGitコマンドを神速で習得しよう! 
    そういえば殆どここにまとまってたななんて今更思い出した。個人使用に慣れてきて、オンラインリポジトリでの多人数開発したいってなったら見るといいかも。

最後に

gitも他の技術同様、実際に使ってみるのがその理解には早いと思います。しかし、バージョン管理という大枠の重要な位置を占める機能であるが故、少しのミスでデータをすべて飛ばす可能性も否定はできません。バージョン管理システムを導入しようとしているのに皮肉な話ではあるのですが、最初の慣れないうちは、プロジェクトのバックアップを手動でとっておくことをおすすめします。ただし、gitはそんなにこわいものではないので、恐れずに使って見てほしいなと思います。 それでは、これを読んだ方がgitの恩恵を受けられることを願っています。

就活について 準備編

はじめに

こんにちは、いなえです。

なんとか就活を終え、とりあえず一息ついたという感じです。 というわけで、多くの人が苦しめられる就活において、少しでも楽に出来ればと思い、記事にしようかと思いました。

最近記事を書いてなかったからとかではないです。ええ。

準備編とか書きましたが現時点でなんか面倒になってきてるのでこれで途絶えるかもしれません。

今回は、主にその就活を実際に始めるにあたっての準備をする段階の話をしようと思います。

準備とはいっても、「インターンに行け」だの「ボランティアをしろ」だの「バイトはしておけ」だのといった、そういう就活アピールに向けた準備ではなく、就職活動がやりやすくなるような準備の事です。

多くの人は自分でやり方を見つけていくんでしょうが、就活が始まるとその試行錯誤にもおそらくメンタルを削られることになると思うので、脳死でこれに倣うのもアリではと思っています。 取り敢えず、参考までに見てもらえれば幸いです。

情報の整理

就職活動において、大切かつ一番面倒なものとして、情報収集があります。
就職活動が始まったからといって企業から勝手に情報が来る、というものでもありません。おそらくほとんどの人がリクナビマイナビといったサイトに嫌々登録し、その中で企業を探し、エントリーをしていくことになると思います。初めの方こそ問題はないのですが、だんだんたくさんある情報を整理するのが面倒になってくると思います。後からやり方を変えようとすると無駄に労力がかかったりするので、適当に始めるよりはこういった方法を取ったほうが良いのではないかと思います。

ソフトウェア的な部分

メールアドレス

就活を始めるとわかるのですが、多くのサイトは登録を要求してきますが、その際に通知を飛ばすメールアドレスを要求されます。
また、何か連絡がある度にマイナビリクナビからメールが届きます。一番使っているアドレスで登録するのが、メールを見ずに重要な連絡(例えば面接の日程の打診など)を見逃す可能性はないのですが、おそらく一番使っているアドレスは、他のメールも来るため、就活関係のメールとそうでないメールが混ざってしまい、後々就活関係だけ見たい時に面倒だったり、多くメールが来ると就活関係の大切なメールが流れてしまったりすると思います。

それを防ぐために、僕は就活専用のメールアドレスを取っておくことを推奨します。

加えて、その中でもGmailのアドレスを取得することをオススメしておきます。

gmailを取得する際にgoogleアカウントが使われますが、これが色々と便利なためです。また、スマホでもPCやタブレットでも確認できるという意味でも、キャリアメールを使うよりもこういったフリーメールを使ったほうが良いのではないかと思います。これは後で話すカレンダー等についても同じです。

カレンダー

就活で一番まずいのは、参加予定の説明会をドタキャンすることになってしまったり、行けると言った日程で面接がバッティングしたりということです。
場合によっては選考それ自体に響きかねないミスはなくしたいですよね。普通ならそんなことほぼないと思うのですが、時期によっては予定がすごい勢いで入ってきて、脳みそだけだと管理できなくなってきます。おとなしくカレンダーを使いましょう。

さて、その上でどれを使えば良いのかですが、僕は先程取ったGmailアカウントでのGoogleカレンダーを使うことをオススメします。コヤツは、スマホのカレンダーに追加しておくと自動で同期を取ってくれるので、PCからもスマホからも予定が見れる上に、追加削除ができるという優れものです。iPhoneでそういったことが出来たのできっとAndroidでも出来ると思います(開発元的な意味で)。

スプレッドシート

Gmailアカウントを使ったサービスについて2つ来たので、流れでいってしまいます。

就活が始まると、特に解禁時期から暫くは、「何処の企業にエントリーしたか」とか「何処の企業がどこまで選考がすすんでいるか」等がわかりにくくなります。勿論リクナビマイナビからエントリーしたのであれば、(UIが壊滅的に悪いので探すのに苦労する可能性があるのは否定しませんが)企業ごとのそれらについては見ることは出来ます。ただし、パッと見て全体の状態は掴めません。
また、リクナビマイナビの両方に載せている企業は、自分がどちらからエントリーしたのかわからなくて困ることがあります。

こういった情報をまとめる方法はいくつかありますが、僕はGoogleスプレッドシートでまとめました。これは所謂Excelの様なものなのです。「じゃあExcelでいいじゃん」となると思いますが、Googleスプレッドシートの利点は今までも何度も言ってきた通りスマホでもPCででも見れるし編集できるところにあります。

このGoogleスプレッドシートというのは、Googleドライブ(Googleが提供しているクラウドサービスと認識してください)上で作成できます。ブラウザ上で編集が可能で、GoogleドライブもGoogleスプレッドシートも、Gmailアカウントを持っていれば無料で利用可能です。Excelと比べると、操作が違ったり、機能が少なかったりしますが、就活の情報をまとめる程度ならこれで充分でした。

僕は一番上の行に、

  • 企業名
  • 志望度
  • 説明会参加日
  • 履歴書締め切り日
  • 筆記or適性試験
  • ES提出締め切り日
  • 一次面接日程
  • 二次面接日程
  • マイページ登録の是非
  • マイページID
  • 経由したサービス
  • 備考
  • マイページURL
  • 応募情報URL

と言った感じで書いておいて、その下の行に企業ごとに色々と書き込んでました。参考までに。自分でいい方法を模索してみてください。

後は、交通費が非常にかさむのでそれを記録していたりしました。色々自動化出来るので楽ですね。

EverNote

説明会や面接など、メールで会場や日時についての連絡が来れば先程のGmailで確認すれば良いのですが、例えば、企業が自社ページを持っていて、「そこに詳細置いておくから見てね」形式だったり、リクナビマイナビに連絡が来るタイプの場合、サッと確認したい時にログインを要求されて面倒だったり、電波の入りにくいところにいる時に開けなかったりして不便です。

そこでEverNoteを活用する事をオススメします。

これは簡単に言うとクラウドメモ帳サービス的な感じなのですが、画像も使えたり、何ならその画像に加工もできたりと実は多機能だったりします。ブラウザに表示されている内容を選択して貼り付けると、そのままの感じで貼り付けてくれます。これを使って自社ページの面接の詳細案内を貼り付けておけば、確認したい時に、IDやPasswordを忘れていても、電波が入らないところに居ても*1すぐに確認できます。
マップで位置を示した画像なんかがあったりしてもそれもコピーしてくれたりするので、そういった点で普通のメモ帳を使うよりも良いと思います。

また、最初は特に忘れがちですが、ESを残しておくのにもEverNoteは有効です。面接などではESの内容を元に色々なことを聞かれたりします。そのESの内容がわからなければ、面接で何を聞かれそうか一切検討がつかず、準備もできません。どこまでESで書いたのかを把握しておくためにもESを残しておくのは重要です。
ESでなくても企業の自社ページのエントリー設問等もコピーアンドペーストするだけで非常に楽です。
また、ESで共通して聞かれる様な自己アピール等についてEverNoteにおいておけば、新しい会社のESを書く際も楽ですし、自己分析についても置いておけばESを書く助けになるかもしれません。
pdfファイルを貼り付けることも出来るので提出したOpenESをそのまま貼っておけるというのも楽ですね。

そしてくどいですが、これもスマホからもPCでからも使えるのも利点です。

交通系アプリ

特に僕が千葉住みという事もあるのですが、都心に出る機会が多くなるので、都内の鉄道周りに詳しいとか、そういう場合でなければ交通系アプリを入れておくのをオススメします。

結構色んな所に行くことになるので、初見の場所に面接の時間に間に合う様に行くというのは意外と神経を使います。当たり前でしょと思う人も多いと思いますが、念の為。

僕はYahoo!乗り換えに非常にお世話になりました。これはMyページに検索した乗換案内を保存したり出来るのでオススメです。

地図系アプリ

流石に殆どの人が入れてると思いますがこれも念の為。駅から遠い場所に行かないといけない事もあったりしますしね。僕はGoogleMapsにお世話になってました。

Twitter

情報収集の為(大嘘)

ハード的な部分

手帳

さっきカレンダーの話をしたので「えっ?」と思う人がいるかもしれませんが、一応用意しておいたほうが良いです。就活が行われるのは大抵は少しフォーマルな場ですし、スマホを取り出すのが憚られる場面というのもあると思います。何故か手帳なら取り出しても社会的に特に問題ないらしいのでこれは用意しておきましょう。

ただし、カレンダーアプリの予定と同期を取っておかないと予定を聞かれた時に困り、意味がありません。注意しましょう。

クリアファイル

こいつが意外と便利かつ重要です。安くてもいいので透明なやつを適当にエントリーする会社の数程度買っておきましょう。説明会や面接などで書類等を渡された時に1つのクリアファイルにまとめておくと非常に楽です。

A社の面接に行く前にA社の書類のすべて入ったクリアファイルを持っていけば、直前にA社のことについて確認できたりもします。

僕はこれをしやすくするために、説明会や面接などでのメモは手帳やメモ帳、ノートではなく、ルーズリーフに取っていました。そしてそれをクリアファイルに入れておけば、全てのアナログな情報は1社あたり1枚のクリアファイルの中に集約されるわけです。管理が楽ですね。

クリップボード

特に合同説明会などにおいて、机が無いという場面は多くあります。ノートやクリアファイルを下敷き代わりにしてもいいですが、僕はクリップボードを買っておくことをオススメします。何なら立ち見でもメモをとるのに困りません。

所謂画板に似たもので、殆どの人が見たことはあるかと思いますがわからなければググってください。

扇子

汗っかきな人は夏近くまで就活がのびるとスーツのせいで非常に困ったことになると思います。扇子やタオルを持ち歩くことは考えておいたほうが良いと思います。

携帯バッテリー

電車の中でスマホをいじるのであれば、あると安心。

スーツやビジネスバッグ等

買わない人はほとんど居ないと思いますが念の為。2着あると安心ですが、結局僕は2着買ったものの、1着しか使いませんでした。むしろ、一人暮らしならば、忙しい時は洗濯が面倒になってしまったりするので、中のカッターシャツは3枚はあったほうが良いんじゃないかと個人的に思います。

人的な部分

就活の話を出来る友達

志望する業界が同じだとなお嬉しいが、違ったとしても共通する一般的な情報が入ってくるのでいるとありがたい。ひとり何も知らず取り残されているかも…という不安は少なくとも小さくなる。Discordで鯖立てて情報交換とかも良いと思います。

まとめ

例によってまとめる能力が無いのでタラタラと駄文を連ねてしまいました。結論から言うと、

ということですね。何だ、僕もうまくまとめられるじゃん。

スマホとPCのどちらからでも見れるということは、思った以上にメリットなので、環境依存レスな感じで就活を進めていきましょう。

ということでお役に立てば良いですが今回はこんな感じで終了です。それでは。

*1:なんか本当は課金しないとローカルで保存されないらしいんですが、キャッシュに残ってるからか普通に見れる

結城 浩 氏著の『Java言語で学ぶ デザインパターン入門』を読んで

結城 浩 氏著の『増補改訂版 Java言語で学ぶデザインパターン入門』を読了しました。記録として、そして他の方の参考のために感想を書いておこうかと思います。

非常に読みやすくわかりやすく、いい本でした。勿論、概念的な部分があるので一度では読み込めず飲み込めない所もありましたが、こちらの理解を促そうとする工夫が要所に感じられ、そういった所も読んでいくことが出来ました。著者の結城浩さんの日本語が僕にとって非常に相性が良かったのか、はたまた誰が読んでもそうなのかはわかりませんが、説明が非常にわかりやすいです。自分にはこういった才能がないと思っているので羨ましい限りなのですが、短い簡潔な文でわかりやすく伝えるという事が非常にうまい方のようで、1文を読んで「あー、なるほど」と知識としてあるものの絡まっていたものが解けるような感覚を何度か味わいました。

ただ、本著の評価自体からは少し外れる話なのですが、自身の知識の再確認が多く(この書き方or考え方使っていたし知っていたけどこういう名前がついていたんだ、とか)、新規性自体は自分の中では大きくなかったです。しかし、その分インターフェースを始めとした色々な考え方の根底にあるものを復習しつつ、知らなかった情報を補足していく形で自分のものに出来たのではないかと思います(勿論、マスターには程遠いですが…)

逆に言うとこれをもっと早くに読んでいれば無駄な試行錯誤もなかったかな、と思います。付録Dにもあるように

デザインパターンが重要なのは、経験を積んだプログラマの知恵を効率良く学ぶことができるから

という事なので、恐らく必死に自分で最適な設計を考えていた時間でこれを読んでいたらもう少し時間がかからなかったのかな、と思います。

因みに言うと、僕は一度この本を途中で読むのをやめたことがあります。Template Methodがイマイチわからなかった、というのがその理由なのですが、当時よくプログラミングについてわかっていなかったことも有り、久々に読んでみるかと引っ張り出してくると、当時わからなかった所もスラスラ読めて楽しくなって全部読んでしまいました。

その上で、これを読むのに苦労している方が居たら言いたいのが、始めのUML図の説明をちゃんと読むこと、Template Methodはちゃんと理解すること、です。

前回よくわからなくて読むのをやめた時には、UML図の説明が面倒で適当に読み飛ばして読み始めてしまったのが原因だと思っています。今回は、応用情報技術者試験の勉強で出てきたことも有り抵抗がなかったのでちゃんと読んだらUML図がきちんと読めるようになって非常に理解が楽になりました。

また、3章Template Methodについては(というか全てのパターンについてなのですが)、わかってしまえば難しいことはないものなので、しっかり理解に努めましょう。そこでインターフェースやsubclass responsibility等についてしっかり理解しておけば、あとは個人的にはそのマイナーチェンジと言うか、やりたいことややり方を変えたバージョンで通底する考え方は似通っているという風に感じたので、恐らくそれほど理解は大変ではないと思います。勿論量が量なので時間はかかるとは思うのですが…

後もう一つ言うことがあるとすると、厳密にわかろうとするより、概念や考え方を理解しようとした方が簡単に読んでいけると思います。何故こういったことをするのか、という話は大体章の終わりの方に解説として載っているので、よくわからなくても章を通して取り敢えず読んでみる、という読み方を個人的にはオススメします。

僕はJavaは過去に1度、非常に簡単なゲーム的なものを作るのにしか使ったことがなく、時間で言うと3時間も触ったことがなく、詳しく言語仕様は知らなかったのですが、C++オブジェクト指向プログラミングをしている人であれば何の問題もなく読めると思います。Java言語で学ぶ、とあたかもJava言語は前提知識かのように書いている割には説明もあったりしたので、プログラミングをしている人なら読めるのではないかと思います。

ただし、勿論とっても簡単、と言うものではないです。ただし、この本を読んで得られるものが多いのは僕は初学者だと思うので、チャレンジしてみることはオススメします。わからなければ少し寝かせておけば良いのです(それこそ僕のように)。いつかわかる日が来て、読めるようになる、と考えて、今はどうせ読めないだろうけど、位の気持ちで読み始めるのが良いのではないでしょうか。

DXライブラリでasserionマクロを使えるようにする

C言語にはassertという関数がある。

詳細は(ここらへん)http://www.c-tipsref.com/reference/assert/assert.htmlを見たりググったりして欲しい。

これは簡単に言ってしまえばプログラマの意図を記述するのに使われる。

例えば、除算を定義する際にゼロ除算を除きたい場合は、assert(割る数!=0)と書いておくと、間違って0で割ってしまった時にそこでプログラムを強制終了して、「割る数!=0が満たされてないよ?」的なメッセージを出してくれる。

さて、これをDXライブラリでも使えるようにしたい。assert関数を使えば良いんじゃないの?と思うかもしれないが、assert関数はプログラムをその場で強制終了する。つまりはDxLib_End関数が最後に呼ばれず、場合によっては変にプロセスが残ったままになってしまう。

解決策として、適当なプログラム全体の管理クラス的なものを作って、そいつのデストラクタにDxLib_End関数を書けば良いのではないか、と思うかもしれないがそうも行かないらしい。assert関数が呼ばれた場合はデストラクタも呼ばれないらしいのだ。

さて、ということで自作assertだ。単にラップすれば良いんじゃないの(=Adopterパターンでなんとかなるんじゃないの)と思うかもしれないが、せっかくなので多少使いやすいものを作りたいと思ってしまった。

そして出来たのが以下である。

assertDx.h

//
//assert
//

//assertionマクロ。こっちをつかう。
//意図していない部分や、ファイル名、何行目か等の情報が得られる。
#define assertDx(assertion) AssertDx(assertion,#assertion,__FILE__,__LINE__,__FUNCTION__)

//assertionマクロ。こっちをつかう。
//意図していない部分や、ファイル名、何行目か等の情報が得られる。
//デバッグ用に情報(std::string)を1つ埋め込める
#define assertDxInfo(assertion,info) AssertDx(assertion,#assertion,__FILE__,__LINE__,__FUNCTION__,info)


//マクロが実際に動く時の中身の関数。こちらではなくassertDxを使う
void AssertDx(bool assert_bool, std::string assert_tex, std::string file, int line, std::string func);

//マクロが実際に動く時の中身の関数。こちらではなくassertDxを使う
//デバッグ用に情報を1つ埋め込める
void AssertDx(bool assert_bool, std::string assert_tex, std::string file, int line, std::string func, std::string info);

assertDx.cpp


//マクロが実際に動く時の中身の関数。こちらではなくassertDxを使う
void AssertDx(bool assert_bool, std::string assert_tex, std::string file, int line, std::string func) {
    if (assert_bool == false) {
        //意図しない動作をしている旨を表示
        MessageBox(NULL, (
            "Assertion failed: \"" + assert_tex +
            "\",\n File:" + file
            + ",\n Line:" + std::to_string(line)
            + ",\n In Function:" + func
            ).c_str()
            , "Assertion failed", MB_OK | MB_ICONSTOP);

        DxLib_End();// DXライブラリ使用の終了処理
        exit(-1);//-1を渡して終了する。
    }
}


//マクロが実際に動く時の中身の関数。こちらではなくassertDxを使う
void AssertDx(bool assert_bool, std::string assert_tex, std::string file, int line, std::string func, std::string info) {
    if (assert_bool == false) {
        //意図しない動作をしている旨を表示
        MessageBox(NULL, (
            "Assertion failed: \"" + assert_tex +
            "\",\n File:" + file
            + ",\n Line:" + std::to_string(line)
            + ",\n In Function:" + func
            + ",\n Infomation:" + info
            ).c_str()
            , "Assertion failed", MB_OK | MB_ICONSTOP);

        DxLib_End();// DXライブラリ使用の終了処理
        exit(-1);//-1を渡して終了する。
    }
}

正直申し上げてよく分からず書いているところがある(特にWinAPI周り)ので動作については保証できないが、一応こんな感じで良い感じに動く。

使い方としては

//読み込みに失敗していない
    assertDxInfo(load_result != -1, handle_name);

として読み込みが失敗しているのにプログラムがそのまま動くのを阻止したりと言った風に使う。(ちなみにこのassertDxInfo関数は、assertion警告が出る時に追加表示する情報を付加できる)

改善点はまだまだありそうだが、今のところ実用に耐えているっぽいので(そもそもそんなに引っかからないので本当に耐えているのかは不明)これでいいかな、という感じだ。

そしてここに晒すことによってマズイ所を指摘してもらえて改善できるのではないかと淡い期待をしているので、何か気付いたことがあったら教えていただけると嬉しい。

変数を簡易に表示する

デバッグをする際に組み込み変数を簡単に表示したい事があると思うのだが、わざわざ毎回

int hoge = 5;
printf("hoge:%d\n", hoge);

みたいなのを書いてたのだけど、"hoge:%d\n"は予測補完聞かないし、毎回書くのは地味に面倒だなあと思っていたのでその辺を簡単に書ける関数マクロを用意してみた。

説明するのも面倒なので取り敢えず以下にコードを示す。

printInstant.h

#pragma once
#include<string>

//debug用マクロこっちをつかう。
//渡した変数が簡易に表示される
#define printInstant(print_var) PrintInstant(#print_var,print_var)

//debug用マクロこっちをつかう。
//渡した変数が簡易に表示される。
//デバッグ用に情報(std::string)を1つ埋め込める
#define printInstantInfo(print_var,info) PrintInstant(#print_var,print_var,info)

int PrintInstant(std::string var_name, int var);

int PrintInstant(std::string var_name, double var);

int PrintInstant(std::string var_name, std::string var);

int PrintInstant(std::string var_name, int var, std::string info);

int PrintInstant(std::string var_name, double var, std::string info);

int PrintInstant(std::string var_name, std::string var, std::string info);

printInstant.cpp

#include"printInstant.h"
#include<stdio.h>

int PrintInstant(std::string var_name, int var) {
    return printf((var_name + " : %d\n").c_str(), var);
}

int PrintInstant(std::string var_name, double var) {
    return printf((var_name + " : %lf\n").c_str(), var);
}

int PrintInstant(std::string var_name, std::string var) {
    return printf((var_name + " : %s\n").c_str(), var.c_str());
}


int PrintInstant(std::string var_name, int var, std::string info) {
    return printf(("(" + info + ") " + var_name + " : %d\n").c_str(), var);
}

int PrintInstant(std::string var_name, double var, std::string info) {
    return printf(("(" + info + ") " + var_name + " : %lf\n").c_str(), var);
}

int PrintInstant(std::string var_name, std::string var, std::string info) {
    return printf(("(" + info + ") " + var_name + " : %s\n").c_str(), var.c_str());
}

使用方法としては

#include"printInstant.h"

int main() {
    int hoge = 5;

    printInstant(hoge);

    return 0;
}

出力

hoge : 5

みたいな感じでprintInstant(変数);と書いてやる。

printInstantInfoは付加情報を付けたい際に使う。

#include"printInstant.h"


int main() {
    int hoge = 5;

    printInstantInfo(hoge,"test now");

    return 0;
}

出力

(test now) hoge : 5

まとめ

C言語のマクロをちゃんと知っている人ならすぐに思いつくのだろうが、僕はあまりそのあたりに詳しくなかったので最近思いついて書いてみた。

今回はprintfprintfDxに書き換えればDXライブラリにも移植がし易いという理由でprintfで描画したが、勿論std::cout等でもいいと思う

わかりやすさのためにグローバルとして宣言したが、本当はもう少し隠蔽について考えたほうが良いのではないかと思う。

変換コンストラクタについて

注意

はじめにことわっておくがこれは備忘録かつ僕の記憶の定着のための記事だ。

という事で気軽に流して欲しい(が、間違いがあれば教えていただけると大変嬉しい)

早速本題

さて、数日前まで恥ずかしながら変換コンストラクタという言葉を僕は知らなかった。使っている癖にだ。

いわゆる変換コンストラクタとは、引数が一つだけのコンストラクタをいう

#include<string>

class Hoge {
public:
    
    Hoge();//デフォルトコンストラクタ(変換コンストラクタではない)

    Hoge(int num);//変換コンストラクタ

    Hoge(std::string str);//変換コンストラクタ

    Hoge(int a, int b);//引数が2つのコンストラクタ。変換コンストラクタではない。

    Hoge& operator =(int num);//=演算子のオーバーロード

    Hoge& operator =(std::string str);//=演算子のオーバーロード

};

という感じ(上から2つめと3つめ)。

これがどうしたの、という感じだけれど、C++ではこやつらは特別な扱いを受けている。

例を見ていこう。

//上のHogeクラスは宣言済みとする
int main() {

    Hoge obj(3);

    return 0;
}

これはまさにHoge::Hoge(int num);を呼んでいるのはわかるだろう。その上で次を見て欲しい。

//Hogeクラスは宣言済みとする
int main() {

    //Hoge obj(3);と同じ
    Hoge obj = 3;

    return 0;
}

一見すると=演算子オーバーロードしたものが呼ばれているように見えるかもしれないが、これは実はコメントにもあるようにHoge obj(3);と書かれているのと同じであり、つまりはHoge::Hoge(int num);が呼ばれている(operator =(int num);*1ではない事に注意)

では、以下の場合を見て欲しい

//Hogeクラスは宣言済みとする
int main() {

    Hoge obj;

    obj = 3;

    return 0;
}

この場合のobj=3;では、何が呼ばれているだろうか?これはHoge::Hoge(int num);ではなく、operator =(int num);*2だ。

だが、上記までと=を使っているという所では変わらない。何が違うのだろうか?

同じ「=」でも…

非常に簡単に言うと、初期化か、代入かが違う。

C++では代入と初期化は明確に区別されている。

この違いを非常に簡単に(誤解を恐れず)書くと、とある型のオブジェクトの宣言時にその値を与える形で定義してしまう際に行われるのが初期化であり、既に生成された後のオブジェクトに値を入れるような処理をするのが代入だ。まあ多分コードを見た方が早い。

int a=5;//これが初期化

int b;

b=5;//これが代入

その上で言うと、operatorによる=の演算子オーバーロード代入演算子を定義している。初期化の=は定義していない。では、初期化の=は一体何なのだろうか。さっきも書いたのでわかると思うが、これが変換コンストラクタの実装として定義されているものだ。

つまりはまとめると、変換コンストラクタに於いては、MyClass(type val);という変換コンストラクタがある場合に、MyClass obj(value);と書くと変換コンストラクタが明示的に呼べるし(valuetype型の値)、MyClass obj=value;と書くことで暗黙的に呼ぶことも出来る。つまり

//Hogeクラスは宣言済みとする
int main() {

    Hoge obj(3);//Hoge(int)が呼ばれた

    Hoge obj2 = 3;//Hoge(int)が呼ばれた

    obj = 5;//operator =(int)が呼ばれた

    obj2 = 7;//operator =(int)が呼ばれた

    return 0;
}

となるわけである。もし、変換コンストラクタによる初期化を=で出来ないようにしたければ、その変換コンストラクタにexplicitキーワードをつければ良い

この辺がわかっていると組み込み型との差を意識しないクラスの実装などをするのが楽なので非常に便利だと思う。

参考ページ

以下、参考にさせていただいたページ。そもそも変換コンストラクタについて教えてくださったいかろちゃん先輩(混乱)には感謝しています。

クラス管理の責任 by いかろちゃん

explicitについて補助的に参考にさせていただいたページ

*1:みやすさのために戻り値を省略しているが気にしない

*2:みやすさのために戻り値を省略しているが気にしない

人文社会科学という学問分野について

導入

先日、TLで少し話があがっていた(というか僕が勝手に語っていた?)ので折角と思って記事にする。

まず、僕は時々人文社会科学と言われるような所謂「文系学問」というものを軽視される事があるように思う。(実は結構この「文型」というくくりも好きじゃないのだが、ここでは触れず伝わりやすさを優先しようと思う) これは事実ではなく感想というか、僕がそう思っているだけであって、もしも「そんなことないよ!」という方が居たら僕は「なるほど、あなたはそう思っている様なので、わざわざこんな議論や主張に首を突っ込まずともいいですよ」で終わってしまう話なので、多分これを読む必要はない。

僕は主にこの話を「人文社会科学が軽視される傾向がある」(若しくはもう少し絞って「人文科学もしくは社会科学が軽視される傾向がある」)と思っている人のうち、特に「人文社会科学は軽視されてしかるべきだ」とか、「人文社会科学は自然科学に劣ったモノだ」といった風に、その軽視に対して肯定的な意見を持っている方々に見て欲しいと思って書いている。

人文社会科学とは

さて、読み始めた人達の一部の人達のうちに人文社会科学ってそもそもなんよ、みたいな人がいるかもしれないので、その辺の説明をしたいのだけど、詳しく話すと(僕が文を短くまとめるのが下手くそということもあって)長くなりそうなので、ここでは割愛させて頂く。恐らくGoogle先生Wikipedia先生に聞いたら概観はつかめるかな、と思う。

また、イメージをつかむのに(こちらの記事)http://readingmonkey.blog45.fc2.com/blog-entry-199.htmlにある画像等がわかりやすい気がしたので参考にすると良いかもしれない。

本題

概要

まず結局のところ僕が言いたいことを、僕のツイートから直接引っ張ってきたのでご覧いただきたい。

社会から人文科学が理解されにくい(と僕は思ってるんだけど)のは、その成果が常識となってしまうところだよなと常々思っている。当たり前だからそれを理論立てて言われても「あ、はい」ってなったりしちゃうんだよね。

それでもそこに至るプロセスに興味がある人が一定数いて、人文社会科学を支えてるんだと思うんだけど、この構図、ゲームエンジンを前にした時に「ヤッターゲーム作れる!!」となるか「どうやって動いてるんだろう?」となるかの違いに似てる気がする

あと、人文社会科学は「不変真理や事実を探求する学問でない」って所を理由に自然科学より劣ったモノとみられることがある気もするんだけど、そこに関しては僕は主観の話かなと思う(学問として体型立てた上で役に立てば良いのか、それとも不変の事実でないといけないのかみたいな

あとそもそも自然科学でも今わかってる事実(法則とか)って「今事実だと思ってること」でしかないよねって話もあったりするしなかなか難しいよなと思う。自然科学がより発展したら今の科学も似非になりうるかなって。そういう意味で不変性の観点で言い合いするとしたら線引は難しそうだなと思う。

現実とか社会をみる定規とか分度器みたいなものを提供してくれるのが人文社会科学かなという感じがする(ので社会に合わせて内容も変わる)。僕はそれも大切だと思うんだけど、不変の(普遍の)真理の追求こそが学問として正統だと言う人の「気持ち」もわからないではない。

ということで伝わったのかわからないのだけど、取り敢えずそんな感じのことが言いたいんだよという事で、もう少し細かく補足等をしながらみていきたい。

人文社会科学が「役立って」いないように見える

価値=有益性論

無意識のうちにかも知れないが、学問の価値のようなモノを考える時にその有益性を見る人が多いと思う。

実際に役に立つのかどうか、というのは即物的だが、非常にわかりやすい話で、わかりやすいということは多くの人はここで直感的にその学問の価値を判断するのだろう。人間は理解をするのにコストがかからない情報ほど進んで取り入れる傾向にあると僕は思っている。

さて、それを前提とした上で、人文社会科学は恐らく「役に立たない」学問としてみられがちなのだろうと思う。それは何故か、というと僕は先で述べたようにその成果が「常識」となってしまうからだとおもっている。

既に公知となっている事による有益性の判断の変化

人文社会科学は、大雑把に言うと人の在り方や社会の在り方を研究対象とする学問だ。すると、その研究の成果等は人や社会の在り方についてのものとなる。古典的なところに立ち返ると、民主主義という概念等がその成果ではないだろうか。これは今となっては当たり前のものであって、何も凄いことではない。(特に「民主主義国家」と銘打つ国家に生まれた以上は)生まれながらにその中にいるし、その中で育っていく。自分にとって当然の枠組みとして受け入れられる事が多いし、頭をひねらずともそこにシステムとして存在するので、考え出さずとも受け入れるだけで良い。

この様に、人文社会科学の成果は社会の中に溶け込んでいく。特に人文社会科学で研究対象とされるような大きな分野については、過去の成果が社会に取り入れられ、僕達にとって「当たり前」のものとなってしまっていることが多い。

人間、「当たり前」というモノにありがたみを感じない。同じだけの利益を得ていても、ある時その利益を初めて受けるようになるのと、ずっとその利益を受けていたのとでは、その利益の感じ方が違うのだろう。(効用の逓減にも近しい話かな?と思うのだけど、自分は経済学は詳しくないのでこの話には踏み込まないでおく)

「失ってからその大切さに気づく」とよく言うように、人間は得ている利益を差分で認識しがちなのだ。得ている利益の量ではなく、利益の量の増減で利益を感じるのだろう。

そうなると、「当たり前」のことに対して一つ一つ順を追って確かめていったりするような人文社会科学が、直接的に利益の増減を感じられないので、「役に立たない」学問に見えてくるのだ。

成果が出るまでの試行錯誤は受け取る側は見えない

また、仮に新しく成果が出たとしても、そこに利益の増減が感じにくいというのもあるのではないかと思う。人文社会科学の成果というのは、この世にある真実の発見ではない。言って見るならば、この世を見る際の「視点」の獲得のようなものなのである。

新たな「視点」にたどり着くのは難しい。しかし一度その「視点」を受け入れてしまえば、その「視点」はなんら新しいものではなくなる。つまり答えを見てからそこまでの道筋を見ると一本道に見えてしまうのだ。そして、その一本道を辿ることが非常に簡単に見える。

しかし、その「視点」が見つかる前は、人々はその「視点」がどこにあるか知らないばかりか、そもそもその「視点」があるかどうかもわからない。今自らの持つ「視点」から、至るべき「視点」に向けて、無数ある道をひたすら思考する。ある道がそもそもどこかの段階で間違っているかもしれないし、ある分岐路でどちらかを選ぶともうどの新しい「視点」にもつながっていないかもしれない。そういった広大な中で何処かにある「視点」を探し続けるのだ。そして、「視点」が見つかると、自分が探し回った道の事については述べず、今自分の持つ「視点」から、新しく見つけた「視点」への道を成果として示す。それは、見る人によっては元からそこにのみ道があったかの様に映るだろう。

そうすると、新たな「視点」の獲得は「当たり前」の事を成果化したものに見える。成果を評価するためにはその「視点」がどういったものか知ることが必要だが、「視点」は知ってしまうと「当たり前」のものになってしまう。「当たり前」のものを成果として出されても利益が増したように見えないので、「役に立って」いるように見えない。よって有益な学問には見えない、と思う人が出て来る、という流れである。

しかし、そうではない、と僕は思う。「人は平等」等の「当たり前」が当たり前でない時代があった。おそらく今も、将来では「当たり前」のことが当たり前の事ではなくそこらじゅうにあるのだろうと思う。過去にはなかった「当たり前」を見つけ出し(もしくは過去の別の「当たり前」を捨て去り)、新しい視点として広げた人がいたように、おそらくこれからもそういう営みが行われていく必要があるだろう。社会は変わっていくのに、同じところからずっと見ているのでは、いずれ見えない影の部分が大きくなっていってしまう。それによって不当な扱いを受けたりする人がいるかもしれない。そういう事を防げるという事はもっと大きな意味を持っていると僕は思う。

そして1つ補足しておきたいが、僕は「人文社会科学において新しい視点の獲得にはたいへん大きな労力がかかるから重要だ」等と考えては居ない。どれだけ大変な事であっても、社会の役に立たなければ少なくとも社会的に意味はないと思う。学問は、その労力からのみで評価されるべきではないと僕は思っている。

人文社会科学は普遍の真理を探求する学問ではない

人文社会科学の研究対象

もう一つ、学問の価値を判断する時に、その学問が普遍の真理の探求を目的とする学問であるか、もしくは成果として普遍の真理が得られる学問であるか、という点を重視する人がいる。

自然科学が一般には普遍の真理の探求を目的としているのに対し、人文社会科学はそうではない。

先程も述べたように人文社会科学は人間や社会といったものを対象とする学問であり、その目的は一般に普遍の真理の探求というものではなく、その人間や社会といったものに法則性を見出したりグループ化をしたりという、視点の獲得が目的となっている。

つまりは、対象となる人間や社会がガラッと変わってしまえばある研究成果は直接的な意味は失ってしまう事が多い。

無人島のたとえ

良く見る例えでいうと、法学や経済学を幾らやっても無人島では役に立たない、というのがある。化学や農学を始め、自然科学は無人島でも役立てられるが、法学者や経済学者はそれを指を咥えてみているしか無い、というものである。

おそらくこの例えを言い出した人は特に経済学についてお金儲けをする学問か何かだと勘違いしているのだろう。それぞれの学問を少しでもやったことがある人達からしたらそもそもこの例えに反論があると思うが、今回はそこには立ち入らない事にする。

さて、人文社会科学を軽視する人達の一部は例えばこの無人島の例等を出して、「それに比べて自然科学はどこでも同じく通じるのでより優れている」だとか、「人文社会科学はだから価値がない」だとかと言う。

しかし、僕はこれについてはそうではないと思う。

まずそもそも、人文社会科学を見る時に自然科学等の他の学問領域を指してどちらが優れているだのと議論する事自体がナンセンスだと思う。職業に貴賎なし、ではないが、僕は学問に貴賎なしという言葉を使いたい。それぞれの学問がそれぞれの領域でより優れたもので有ることに意味を置くとしても、それらの領域をまたいでわざわざ他の領域より自らが優れているとするのは無意味だ。そしてそもそも、それらの価値を計る統一的な尺度など存在しはしないだろう。それなのに一部分を取り出して評価して、その評価を大局的に適用する様な論は筋が通らないと僕は思う。そもそも学問に価値を観念できるのか、という点について本当はもう少し考えたいが、出来るとしても、この考えについてはおかしいだろうと僕は思う。

また、自然科学は言ってみれば自然の中の法則を見つけ出そうとする学問であり、人文社会科学は人や社会の中に法則を見つけ出そうとする学問だ。その性質上、人や社会の存在しない無人島というフィールドを選んで人文社会科学の価値を考えようというのは無理があるのではないだろうか。

真理の探求か真理の獲得か

そして、もう一つ思うことがある。「普遍の真理の探求を目的とする学問でない」として人文社会科学を軽視するのではなく、「普遍の真理を得る学問でない」として人文社会科学を軽視する人が居るのだが、それには少し無理がないか、ということだ。つまりはどういうことかというと、そのような人達は自然科学は普遍の真理を得る学問であり、その点で優位性があると言いたいわけである。

この点について僕は、自然科学は普遍の真理の探求をする学問だとは思っているが、普遍の真理を得る学問だとは必ずしも考えていない。自然科学が得ている成果と呼ぶべきものたちだって、僕は「現時点では普遍の真理に見えるもの」以上のものではないと思うのだ。

例えば公理が本当に正しいかはわからないし、仮説から実験を経て得られた知識だって、本当にそれが普遍の真理かを証明する手立てはない。屁理屈のようだが、実際に普遍の真理だと思われていたものがひっくり返った事だってあった。

例外がないことの証明をそういった所まで求めるのは悪魔の証明ではないかと思うけれど、だからこそ、普遍の真理を得ているとは言えないのではないか、と思う。

自然科学は、自然に属するもろもろの対象を取り扱い、その法則性を明らかにしようとする学問であり、その法則性を明らかにする学問であるけれど、それが普遍の真理かどうかという話とは別だろうと僕は思う。普遍の真理に近づくために(普遍の真理があるのか、みたいな哲学の話は全く詳しくないのでこれも触れないで)その思慮の及ぶ範囲での法則性を明らかにする学問を、普遍の真理を得る学問と言ってしまうのは少し言い過ぎではないだろうか。

結局のところ、法則性を明らかにするというそれは所謂自然に対する視点の獲得であると思う。人文社会科学と違うのはその対象がその有り様を大きく変えるということが一般には無いことではないだろうか。

そして、どちらの視点にも言えることは、正しいと思っていたある視点が実は間違っていたということが無いという保証があるわけではないということだ。

結局、自然科学が普遍の真理を得る学問かというとそれは怪しい。もちろんこれは人文社会科学だって同じだ。一般に信じられているから普遍の真理かというと、それはわからない。よってその学問から得られるのが普遍の真理かどうか、に主眼を置くのは少しおかしいと思う。

せめて目的を何としているか、なら少し話は変わってくるかもしれない。真理の探求を目的としている、という事そのものは嘘ではないだろう。だが加えて、何を目的としているか、でその学問の優劣をつける事が出来るのかという事については僕は疑問に思う。そこに意味はあるのか、というのはあるし、目的に価値が観念できるのか、という話は極めて難しい。

結局見方の話

中身が気になる?

さて、僕はここまで述べたように人文社会科学を劣ったものとは考えていない。自然科学も含め、全ての学問という学問に携わっている人達を等しく尊敬している。

そして、人文社会科学を軽視している人達もそう考えてくれるようになったら良いなと思っている。

さっき概要で引用した中にこういったものがあった。

それでもそこに至るプロセスに興味がある人が一定数いて、人文社会科学を支えてるんだと思うんだけど、この構図、ゲームエンジンを前にした時に「ヤッターゲーム作れる!!」となるか「どうやって動いてるんだろう?」となるかの違いに似てる気がする

「そこに至るプロセス」の「そこ」というのは常識となってしまった人文社会科学の成果とでも言うべきもの、を指している。

ゲームエンジンとは、ゲームを作る際に必要な各種機能を比較的簡易な形で提供してくれるものだ。これを使ってゲームを作るのに、このゲームエンジンがどうやって作られているのかを隅から隅まで把握する必要はない。言われたとおりに使っていればゲームは作れる。

自動車なんかもそうだろう。エンジンからラジエーターからタイヤから何から何までその仕組を詳しく把握している人はそうそういないだろう。でも、アクセルを踏んだら進んで、ブレーキを踏んだら止まる、これに加えて幾つかのことを知っていれば問題なく運転できる。*1

では、自動車を作るとなったらどうだろう?若しくは自動車を改良したり、全く新しいシステムを使った自動車を開発する事を考えたら?勿論実際には専門家が分業もするのだろうけど、全体について詳しく把握している人は必要だろう。そういう人がいないと自動車はいつまでも今のままだ。いつまでたってもリッターあたりの走行距離は変わらないし、自動運転システムなんかがつくことも未来永劫ない。

僕は人文社会科学についても同じようなものなのではないかと思う。民主主義がどういった経緯で出てきたのか、そんなことは知らなくても民主主義の大枠は理解できる。しかし民主主義が行き詰まりを見せたとしてそれに変わる新しいパラダイム*2が必要になったとき、大枠で理解しているだけの人にそれを考えることが出来るのだろうか?僕は出来ないと思う。

そこで僕達が常識だと思っている、「当たり前」化してしまっている、人文社会科学の成果について、1つずつ紐解いて、誰かが考え続けていないといけない。人や社会は変わっていくのだから。

そうなった時にその常識が常識になったプロセスに興味がある人達がその役目を担うのではないかと思う。つまり何が言いたいかって、僕はそもそも最初に出てきていた役に立たないを正面から否定したい訳だ。

「自動車の中身の仕組みなんて詳しく知らなくたって走れるじゃん」と言われたら確かにそうだと思う。でも、「だから自動車の中身の仕組みについて学ぶのは無駄だ」と言われたらそれは違うと思う。

同じように「人文社会科学なんて知らなくたって生きていけるじゃん」と言われたら確かにそうだと思う。でも、「だから人文社会科学について学ぶのは無駄だ」と言われたらそれは違うと思う。

まとめ

初めに僕が言おうとしていたことと、書き進めるうちに結局違うことを言っているところもある気がするけれど、僕が言いたいのはこんなところだった。ひたすらに書き連ねて言ったので読み辛かったと思うが、ここまで読んでいただいた事に感謝したい。

結局のところ、僕は自分が法学を専攻しているので、人文社会科学が劣っていると言われて焦りのようなものを感じていたのかもしれない。人文社会科学への軽視を見て、それを学ぶ自らへの軽視を恐れたのだと思う。

しかしこう書ききって割とスッキリした心境で書くと、結局のところ自然科学であれ人文社会科学であれ、その習熟によってその(所謂社会的「価値」としての)有益性は決まってくるのだから、自分が出来ることをすれば良いのだろうなという思いでいる。

また、僕は人文社会科学を勝手に代表し、知っているかのような顔で人文社会科学について散々語ってきたが、勿論専攻は法学で、その法学さえまともに理解できているかわからない。よって、人文社会科学を専攻している人からもそこは違うぞと思うところがあるかもしれない。

自然科学を専攻している人からはより多くの指摘がありそうな気がする。

是非そういったことがあれば教えていただきたい。例えそもそも人文社会科学が劣っている、という主張であってもだ。僕の感情としてはそういったものは否定したいのだけれど、もし筋が通っていて否定のしようがなければ受け入れざるを得ないだろうし、そうしたらまた新しい「視点」が得られるかもしれない。理論的でない批判はやめていただきたいが、そうでなければ是非皆さんの意見をお伺いしたい。

最後に、二度目だがここまで読んでいただいた事に感謝したい。これが何かあなたの為になればと思う次第である。

*1:カプセル化っぽい話で楽しい

*2:誤用と言われるかもしれないが所謂思考を決める大きな枠組みの意味で使っている