知る、ということ
朝、出社前にこどもをバス停まで送っていくと、いつも同じ時刻に通りかかるおじいさんがいます。ニコニコとこどもの顔を覗きこんでは何も言わず、とぼとぼと歩いていくおじいさん。
最近私も歩くようにしています。会社帰りに1駅くらい歩くだけ。いつまで続くかな。
脳が壊れた、という本を読みました。
- 作者: 鈴木大介
- 出版社/メーカー: 新潮社
- 発売日: 2016/06/16
- メディア: 新書
- この商品を含むブログ (4件) を見る
脳梗塞後のリハビリでの体験や、周囲との関わり方、脳梗塞によって今までできていたことができなくなったことで初めてきづいたことを著者は「僥倖」としてポジティブに捉えています。
ぎょうこうと読みます。思いがけない幸運という意味です。
実際に読んでみて「見えない障害」と言われる高次脳機能障害について、私は知らなさすぎでした。
症状の中に、感情失禁というものがあるそうです。感情を抑えることができず泣き出してしまったり、言葉に詰まったり。赤ちゃんを見ると嬉しい気持ちになってニヤニヤしてしまったり。
そういうことだったのか。知らなさすぎた。
もしかしたら、朝のおじいさんも大変な思いをしてリハビリしているのかも。なんだか切なくなってきた。
知らなかったことを知ることで、見え方は変わる。
いろんなことに気づかせてくれる本でした。読んでよかった。僥倖。
クリエィティブに仕事をしよう。
今日のお昼ごはんはいつもと違う"ヘルシーデリ"なるお弁当を買ってみました。
お店の明るい雰囲気の惹かれてふらふらと。
会社に戻ってお弁当を開けてみるとおしゃれなお弁当箱。
入ってるおかずはふつうのお弁当と大差ないんだけど、いつもよりちょっとだけ気分がいい。ヘルシーやし。おしゃれやし。
おかげさまで社内でも「何そのお弁当?」と人気者になれました。
お弁当も入れ物や呼び名ひとつで、その価値は変わるんだなと。
お弁当を売るならこだわるのはごはんやおかずだけじゃない。お弁当の容器ひとつ販売員さんの売り方ひとつが、口コミになってインターネット上に流れて、新しいお客さまを連れてきてくれるかもしれない。
若いころはクリエイティブな仕事とそうでない仕事があると思ってたけど、 年とって思うのは仕事の内容じゃなくてクリエイティブに仕事するかどうかだってこと。
クリエィティブに作られたお弁当を食べてそう思った。
クリエィティブに仕事をしよう。
Java 例外オブジェクトの生成について
ここでは簡単な計算機プログラムを作成して例外処理について考察します。
Part1
次の計算機クラス(Calculator)は0による除算時に例外をスローします。
計算機クラス
package example; public class Calculator { public int divide(int x, int y){ return x / y; } }
引数 y が0のとき例外が発生します。
Mainクラス
package example; public class Main { public static void main(String[] args) { Calculator calc = new Calculator(); // int result = calc.divide(9, 3); int result = calc.divide(9, 0); System.out.println(result); } }
実行結果
Exception in thread "main" java.lang.ArithmeticException: / by zero at example.Calculator.divide(Calculator.java:6) at example.Main.main(Main.java:8)
Arithmeticとは "算数" という意味です。
Part2
次に独自の例外クラス(CalculatorException)を作成してみます。
計算機例外クラス
package example; public class CalculatorException extends Exception { }
例外クラスを作成する場合はExceptionクラス(およびそのサブクラス)を継承します。Exceptionクラスを継承すると検査例外クラスになります。RuntimeExceptionを継承した場合は実行時例外クラスになります。
計算機クラス
package example; public class Calculator { public int divide(int x, int y) throws CalculatorException{ if (y == 0) { throw new CalculatorException(); } return x / y; } }
CalculatorExceptionは検査例外クラスであるため、例外処理(try-catch or throws)が必須になります。
Mainクラス
package example; public class Main { public static void main(String[] args) { Calculator calc = new Calculator(); try { // int result = calc.divide(9, 3); int result = calc.divide(9, 0); System.out.println(result); } catch (CalculatorException e) { e.printStackTrace(); } } }
CalculatorクラスのdivideメソッドはCalculatorExceptionをスローします。CalculatorExceptionは検査例外クラスであるため、例外処理(try-catch or throws)が必須になります。
実行結果
example.CalculatorException at example.Calculator.divide(Calculator.java:7) at example.Main.main(Main.java:8)
Part1の実行結果と比較してみましょう。
e.printStackTrace();
変数eに対してprintStackTraceというメソッドを呼び出しているだけです。変数eはCalculatorException型の変数です。printStackTraceメソッドは例外情報(例外クラス名、メッセージ)とスタックトレース(メソッド呼び出しの履歴)を出力します。
例外クラス名: メッセージ スタックトレース .. スタックトレース
Part2.5
独自の例外クラス(CalculatorException)にはメッセージを含むこともできます。
計算機例外クラス
package example; public class CalculatorException extends Exception { public CalculatorException(String message){ super(message); } }
スーパークラス(Exception)のコンストラクタにメッセージを設定すると、printStackTraceメソッドの中にメッセージを含むことができます。また設定したメッセージはgetMessageメソッドによって取得可能です。
計算機クラス
package example; public class Calculator { public int divide(int x, int y) throws CalculatorException{ if (y == 0) { throw new CalculatorException("/ by 0"); } return x / y; } }
Mainクラス
package example; public class Main { public static void main(String[] args) { Calculator calc = new Calculator(); try { // int result = calc.divide(9, 3); int result = calc.divide(9, 0); System.out.println(result); } catch (CalculatorException e) { e.printStackTrace(); // System.out.println(e.getMessage()); } } }
実行結果
example.CalculatorException: / by 0 at example.Calculator.divide(Calculator.java:7) at example.Main.main(Main.java:8)
Exceptionクラスのコンストラクタにはメッセージ以外にも、原因を表す例外オブジェクトを設定することもできます。これを使うと原因を表す例外オブジェクトを別の例外オブジェクトでラップすることができます。原因を表す例外オブジェクトはgetCauseメソッドで取り出すことができます。
Part3
独自の例外クラスを作成せずに、JavaのAPIに含まれる標準的な例外クラスを利用することもできます。
計算機クラス
package example; public class Calculator { public int divide(int x, int y) { if (y == 0) { throw new IllegalArgumentException("y is zero"); } return x / y; } }
IllegalArgumentExceptionは不正な引数を表す例外クラスです。IllegalArgumentExceptionはRuntimeExceptionのサブクラスであるため実行時例外に分類されます。
Mainクラス
package example; public class Main { public static void main(String[] args) { Calculator calc = new Calculator(); try { // int result = calc.divide(9, 3); int result = calc.divide(9, 0); System.out.println(result); } catch (IllegalArgumentException e) { e.printStackTrace(); // System.out.println(e.getMessage()); } } }
catchする例外クラスをIllegalArgumentExceptionに変更しています。実行時例外の例外処理(try-catch or throws)は任意です。
実行結果
java.lang.IllegalArgumentException: y is zero at example.Calculator.divide(Calculator.java:7) at example.Main.main(Main.java:8)
参考:その他の標準的な例外クラス
会社組織で学ぶJavaの例外処理入門
Javaの例外処理についてサンプルプログラムを作ってみました。ここでは会社組織のおける部長(GeneralManager)、課長(SectionManager)、一般社員(Employee)クラスを作って組織的に仕事をする様子を実装してみます。
- GeneralManager
- 部長クラス。受け取った仕事を課長にお任せ(委譲)する。ただし、課長の対処しきれない仕事はどんな仕事でも片付ける。
- SectionManager
- 課長クラス。受け取った仕事を一般社員にお任せ(委譲)する。一般社員が対処しれない仕事に対処するが、それでも無理な仕事は部長にお返しする。
- Employee
- 一般社員クラス。受け取った仕事を処理する。無理な仕事は課長にお返しする。
- Task
- 仕事を表すクラス。仕事の名前と作業量を保持する。
- TaskOverException
- 対処しきれない仕事を表す例外クラス。
- Main
- maimメソッドを実装したクラス。
Javaプログラミング
まずは単純なTaskクラス、TaskOverExceptionクラスを作成し、次にEmployee、SectionManager、GeneralManagerクラスを作成します。そのあとMainクラスを作成して動作確認します。
Task
Taskクラスはタスク名と作業量を保持します。
package example; public class Task { private String name; private int volume; public Task(String name, int volume) { this.name = name; this.volume = volume; } public String getName() { return name; } public int getVolume() { return volume; } }
TaskOverException
TaskOverExceptionクラスは作業量超過を表す例外クラスです。
package example; public class TaskOverException extends Exception { }
Employee
Employeeクラスは作業量が5以下の仕事を処理します。作業量が多すぎる場合はTaskOverExceptionをスローします。
package example; public class Employee { public void execute(Task task) throws TaskOverException { if (task.getVolume() <= 5) { System.out.println("Employee#execute " + task.getName()); } else { throw new TaskOverException(); } } }
SectionManager
SectionManagerクラスは、Employeeクラスに処理を移譲します。SectionManagerはTaskOverExceptionを捕捉して処理します。このとき作業量が10以下の仕事を処理可能です。作業量が多すぎる場合はTaskOverExceptionをスローします。
package example; public class SectionManager { private Employee employee; public void setEmployee(Employee employee) { this.employee = employee; } public void execute(Task task) throws TaskOverException { try { employee.execute(task); } catch (TaskOverException e) { if (task.getVolume() <= 10) { System.out.println("SectionManager#execute " + task.getName()); } else { throw e; } } } }
GeneralManager
GeneralManagerクラスは、SectionManagerクラスに処理を移譲します。GeneralManagerはTaskOverExceptionを捕捉して処理します。
package example; public class GeneralManager { private SectionManager sectionManager; public void setSectionManager(SectionManager sectionManager) { this.sectionManager = sectionManager; } public void execute(Task task) { try { sectionManager.execute(task); } catch (TaskOverException e) { System.out.println("GeneralManager#execute " + task.getName()); } } }
Main
Mainクラスにはmainメソッドを実装します。
package example; public class Main { public static void main(String[] args) { GeneralManager generalManager = new GeneralManager(); SectionManager sectionManager = new SectionManager(); Employee employee = new Employee(); generalManager.setSectionManager(sectionManager); sectionManager.setEmployee(employee); Task smallTask = new Task("SmallTask", 1); generalManager.execute(smallTask); Task mediumTask = new Task("MediumTask", 10); generalManager.execute(mediumTask); Task largeTask = new Task("LargeTask", 100); generalManager.execute(largeTask); } }
実行結果
mainメソッドの実行結果は次のようになります。
Employee#execute SmallTask SectionManager#execute MediumTask GeneralManager#execute LargeTask
まとめ
自分で対処できない仕事は上司に報告するようにしましょう。
下手なアドバイス入門
プログラミング講師として受講者にアドバイスをする機会が多くあります。そこで気づいた失敗例をまとめました。
- 信頼関係が構築できていない
- 求められていない
- 前提が共有できていない
- 当たり前のことを言う
- 具体性がない
- えらそうに言う
- 自分ができていないことを言う
1. 信頼関係が構築できていない
アドバイスは両者の信頼関係の上で成立します。相手が貴方のことを信頼していないとアドバイスは無視されます。日頃からの信頼関係が構築できていないのなら、アドバイスするのは控えておきましょう。あなたが部下を指導したいなら、まずは信頼関係を構築するべきです。
2. 求められていない
アドバイスはタイミングが命です。求められていないときにアドバイスをしてはいけません。上司と部下の関係、先輩と後輩の関係など、アドバイスを交わす両者に上下関係がある場合は特に注意しておきましょう。部下はいつもアドバイスを求めているとはかぎりません。アドバイスってのは、相手が求めているときにそっと提供してあげるべきです。
3. 前提が共有できていない
相手の言い分を理解できていないのに、アドバイスしてはいけません。まずは相手のメッセージを理解しましょう。話してあげることよりも聞いてあげることを優先すべきです。
4. 当たり前のことを言う
アドバイスというのは相手に役にたつものでないといけません。相手が気づいていないことを気づかせるのがアドバイスの価値です。当たり前のアドバイスには価値はありません。
5. 具体性がない
行動に結びつかないアドバイスには価値はありません。アドバイスは抽象的にすればするほど「がんばれ」や「やるしかない」といった自明なものになります。悩んでいる人にとってはイラつかせるだけで、逆効果になるかもしれません。
6. えらそうに言う
アドバイスは「何を言うかよりどう言うか」です。アドバイスを交わす両者に上下関係がある場合は特に注意しておきましょう。
7. 自分ができていないことを言う
アドバイスは「どう言うかより誰が言うか」です。アドバイスをするときには、それを言うべき資格が自分にあるのか自問するようにします。
フレームワーク初学者のためのSpark Framework入門
http://postd.cc/java-micro-frameworks-the-new-trend-you-cant-ignore/
Javaのフレームワーク事情
Javaに限らず、Webアプリケーション開発の世界ではフレームワークを使って開発することが一般的です。JavaにはSpringフレームワークや標準のJavaEEなど多くのフレームワークが存在しますが、これらのフレームワークは様々な要件を満たすため、多くの機能が含まれています。そのため、フレームワーク初学者にとって、フレームワークとはどういうものかを学習するという意味では全体像が掴みにくく、学習コストの高いものになっています。
昔はStrutsを勉強して、それからHibernateを勉強して、それからSpringやSeasar2を勉強する、という流れがありました。最近はいきなりSpringから入ることが多い?ようなので大変だろうなと思っています。Spring Bootもよさげですけどね。
マイクロフレームワーク
2016年現在、Webフレームワークの標準を作っているのはやはりRuby on Railsでしょう。Railsからインスパイヤされた(であろう)Webフレームワークは言語を問わず数多く存在します。これらは大変素晴らしいフレームワークですが、小さなWebアプリを開発する場合、たとえば簡易な掲示板を作成するようなシーンにおいては、やや大げさなものになります。
Railsが登場した後、Ruby界隈で、SinatraというWebアプリケーションフレームワークが注目されるようになります。SinatraはRailsとは違って、シンプルで軽量なフレームワークです。簡単に言えば、HTTPリクエストと処理を関連づけるルーティング処理だけを実装したフレームワークです。またDSLで簡潔に処理を記述できるところも特徴の一つです。具体的には次のようなコードを実装します。
require 'sinatra' get '/hi' do "Hello World!" end
初めて見るとRubyのコードなの?という印象を受けるかもしれませんが、これはRubyの文法にしたがって記述されています。getというキーワードがありますが、これはHTTPのGETリクエストを処理することを意味しており、'/hi'の部分はURLを意味しています。つまり、GETリクエストで'/hi'というURLが要求された場合、あとのdo - endブロックが実行され、レスポンスとして"Hello World"が返却される仕組みになっています。
特定のドメイン(目的)に特化したコード表記法をDSL(Domain Specific Language)と呼びます。Sinatraの場合はHTTPのルーティングに特化した表記法と考えることができます。こうすることで直感的で読みやすいコードを作ることができます。
Spark Frameworkとは
SparkはJavaで実装されたマイクロフレームワークです。Java8構文に従うことで少ない労力でWebアプリケーションを開発できます。
ドキュメントが充実しているので、APIの使い方を一通り見ておくと良いでしょう。
http://sparkjava.com/documentation.html
チュートリアル1 - Hello World
ここではMavenでプロジェクトを作成し、Sparkフレームワークを使ったWebアプリケーションを作成します。また、Eclipseで開発できるようにプロジェクトをカスタマイズします。
まずはMavenでプロジェクトの雛形を作成します。グループIDはcom.example、アーティファクトIDはspark-appとしています。
$ mvn archetype:generate -DgroupId=com.example.app -DartifactId=spark-app -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false
プロジェクトが作成されたら、cd spark-appを忘れないように実行しておきましょう。
次にpom.xmlを開いて、
<dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-core</artifactId> <version>2.5</version> </dependency>
コンパイラーの設定を更新しておきましょう。pom.xmlに以下の設定を追加します。urlタグの後(dependenciesタグの前)に追記します。
<properties> <encoding>UTF-8</encoding> <project.build.sourceEncoding>${encoding}</project.build.sourceEncoding> <project.reporting.outputEncoding>${encoding}</project.reporting.outputEncoding> <java.version>1.8</java.version> <web.version>3.1</web.version> </properties> <build> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <version>3.1</version> <configuration> <source>${java.version}</source> <target>${java.version}</target> </configuration> </plugin> </plugins> </build>
次にEclipseで作業できるように以下のmvnコマンドを実行します。
$ mvn eclipse:eclipse
これはeclipseプラグインのeclipseゴールを指定しています。mvnコマンドにはフェーズやゴールといった引数を指定できます。mvn eclipse:eclipseによってEclipseプロジェクトとして必要な設定ファイルが作成できます。
mvn eclipse:cleanコマンドを実行すると設定ファイルを削除できます。
次にApp.javaを開いて、以下のように処理を実装します。import static spark.Spark.*; の指定を忘れないようにしてください。
package com.example.app; import static spark.Spark.*; import spark.Request; import spark.Response; import spark.Route; public class App { public static void main(String[] args) { get("/hello", new Route() { @Override public Object handle(Request req, Response resp) throws Exception { return "Hello World"; } }); } }
完成したApp.javaを実行します。サーバが起動するので以下のURLにアクセスします。
http://localhost:4567/hello
ブラウザに"Hello World"が表示されればOKです。
結果を確認したらApp.javaを忘れずに停止しておきましょう。Consoleビューの赤いボタンを押すとApp.javaは停止します。標準ではTomcatのようにオートリロードされないので、コードを修正する度にプログラムを再起動する必要があります。
チュートリアル2 - リクエストパラメータの表示
mainメソッドの中に2つ目のルーティング( “/echo")を追加してみましょう。ここではクエリパラメータではなく、URLの一部をリクエストパラメータと受け取るようにしています。
get("/echo/:name", new Route() { @Override public Object handle(Request req, Response resp) throws Exception { return "echo:" + req.params("name"); } });
完成したApp.javaを実行します。サーバが起動するので以下のURLにアクセスします。
http://localhost:4567/echo/Hello
ブラウザに"echo:Hello"が表示されればOKです。
チュートリアル3 - ビューテンプレートの使用
Thymeleafのインストール
Sparkは様々なビューテンプレートをサポートしています。ここではSpringでよく利用されるThymeleafを使ってみます。Thymeleafの詳細な情報については以下の公式サイトを参考にしてください。
thymeleaf
thymeleaf-日本語
SparkフレームワークからThymeleafを利用するためにMavenのpom.xmlに以下のライブラリを追記します。Sparkフレームワークの定義の下に追記すると良いでしょう。
<dependency> <groupId>com.sparkjava</groupId> <artifactId>spark-template-thymeleaf</artifactId> <version>2.3</version> </dependency>
それからThymeleafのビューテンプレートを配置するディレクトリを作成しておきましょう。アプリケーションのルートフォルダで以下のコマンドを実行します。
$ mkdir -p src/main/resources/templates
Windowsの場合は mkdir src¥main¥resources¥templatesとしてください。
次にEclipseに更新を反映するために以下のmvnコマンドを実行します。
$ mvn eclipse:eclipse
その後Eclipse側でプロジェクトを選択して、Refreshを選択してください。thymeleafが反映されます。
Thymeleafを使うには
mainメソッドの中に3つ目のルーティング( “/books")を追加してみましょう。/booksではshopNameとbooksをモデルとして作成し、ビューにレンダリングします。
get("/books", new TemplateViewRoute() { @Override public ModelAndView handle(Request req, Response resp) throws Exception { Map<String, Object> model = new HashMap<>(); model.put("shopName", "MyBookStore"); List<String> books = Arrays.asList("Java Book", "PHP Book", "Ruby Book"); model.put("books", books); return new ModelAndView(model, "index"); } }, new ThymeleafTemplateEngine());
getメソッドの第2引数にはこれまでのRouteインタフェースではなく、TemplateViewRouteインタフェースを指定している点に注意してください。TemplateViewRouteインタフェースは戻り値にModelAndViewオブジェクトを返却します。ModelAndViewにはバインドするモデルと、レンダリングするビューのプレフィックスを指定します。プレフィックスには"index"を指定しているので、src/main/resources/templatesディレクトリにあるindex.htmlが呼び出されるようになります。
ビューテンプレート(index.html)の作成
Thymeleafのビューテンプレートindex.htmlを作成します。
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>BookStore</title> </head> <body> <h1 th:text="${shopName}">BookStore</h1> <ul> <li th:each="book : ${books}" th:text="${book}">hoge</li> </ul> </body> </html>
ThymeleafはXMLのバリデーションが働くのでタグの閉じ忘れに注意してください。
それではApp.javaを実行します。サーバが起動するので以下のURLにアクセスします。
http://localhost:4567/books/
ショップタイトルと本の一覧が表示されればOKです。
例外処理について
ビューファイル名を間違えたり、Thymeleafで正しくデータバインディング出来ない場合は例外が発生します。標準では例外のスタックトレースが表示されないので、ルーティング定義の後に、以下のように例外ハンドラを定義しておきましょう。
exception(Exception.class, new ExceptionHandler() { @Override public void handle(Exception e, Request req, Response resp) { e.printStackTrace(); resp.status(200); resp.body(e.getMessage()); } });
これでルーティングの中で例外が発生しても、コンソールにスタックトレースが表示されるようになります。
App.java
ここまでのApp.javaプログラムを再掲しておきます。
package com.example.app; import static spark.Spark.*; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import spark.ExceptionHandler; import spark.ModelAndView; import spark.Request; import spark.Response; import spark.Route; import spark.TemplateViewRoute; import spark.template.thymeleaf.ThymeleafTemplateEngine; public class App { public static void main(String[] args) { get("/hello", new Route() { @Override public Object handle(Request req, Response resp) throws Exception { return "Hello World"; } }); get("/echo/:name", new Route() { @Override public Object handle(Request req, Response resp) throws Exception { return "echo:" + req.params("name"); } }); get("/books", new TemplateViewRoute() { @Override public ModelAndView handle(Request req, Response resp) throws Exception { Map<String, Object> model = new HashMap<>(); model.put("shopName", "MyBookStore"); List<String> books = Arrays.asList("Java Book", "PHP Book", "Ruby Book"); model.put("books", books); return new ModelAndView(model, "index"); } }, new ThymeleafTemplateEngine()); exception(Exception.class, new ExceptionHandler() { @Override public void handle(Exception e, Request req, Response resp) { e.printStackTrace(); resp.status(200); resp.body(e.getMessage()); } }); } }
マイクロフレームワーク、シンプルでいいですね。
Java8で書く
もっとシンプルです。
package com.example.app; import static spark.Spark.exception; import static spark.Spark.get; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import spark.ModelAndView; import spark.template.thymeleaf.ThymeleafTemplateEngine; public class App { public static void main(String[] args) { get("/hello", (req, resp) -> "Hello World"); get("/echo/:name", (req, resp) -> "echo:" + req.params("name")); get("/books", (req, resp) -> { Map<String, Object> model = new HashMap<>(); model.put("shopName", "MyBookStore"); List<String> books = Arrays.asList("Java Book", "PHP Book", "Ruby Book"); model.put("books", books); return new ModelAndView(model, "index"); } , new ThymeleafTemplateEngine()); exception(Exception.class, (e, req, resp) -> { e.printStackTrace(); resp.status(200); resp.body(e.getMessage()); }); } }
Java8いいですね。
プログラミング習得の法則
もうすぐ6月も終わります。この記事は4月から入社して、新入社員研修で初めてプログラミングを学んだ方へのメッセージです。
はじめに
プログラミングメンター(指導者)の仕事をしていると、プログラミングの習得には3つのステップがあることに気づきます。
- 覚える
- わかる
- できる
ここでは覚える、わかる、できるの違いについて考察します。
ステップ1:覚える
初めてプログラムを学ぶとき、変数や配列、if文やfor文といった様々なルールを覚えないといけません。プログラミング習得の第1歩は「覚える」ところからスタートします。たとえばJavaプログラミングを習得する場合は、次のようなプログラムを書くところから始まります。
public class Main { public static void main(String[] args) { System.out.println("Hello World"); } }
これはHello Worldプログラムという有名なものですが、学び始めの頃は、publicってなんだろう、staticってなんだろう、voidって?という状態です。最初の頃は一つひとつのキーワードを無理して読み解こうとせずに、まずはこのとおり書けば動くということを「覚える」ところが大切です。「ぱぶりっくすたてぃっくぼいどめいん・・・」と何度も読んで(ときには復唱して)覚えます。「覚える」ためには読む、聞くといったインプット作業が中心となります。
ステップ2:わかる
コードの書き方を「覚えた」として、次の段階に進むには「覚える」から「わかる」へステップアップする必要があります。それでは「覚える」と「わかる」の違いはどこにあるのでしょうか。
System.out.println("Hello World");
たとえば上記のコードを見て「標準出力へHello World文字列を出力している」とか「Systemクラスのstatic変数outのprintlnメソッドを呼び出している」とか、自分の言葉でコードを解説できる人は「わかっている」人です。「覚える」と「わかる」の違いは単純で、自分の言葉で説明できるかどうかです。
「覚える」から「わかる」の段階へステップアップするためには、覚えたことを自分の言葉で説明する練習をすれば良いのです。自分の言葉で説明する場合、説明した内容を評価してくれる相手が必要です。相談できるメンターや共に学ぶ仲間の身近にいることはプログラミングの理解を深める大事な要素になるでしょう。
自分の言葉で説明するとは、話すという動作に限定するわけではありません。このブログのように文章にしてみるのも、自分の言葉で説明する練習の一つです。自分の言葉で説明するとは覚えた知識をアウトプットすることなのです。
ステップ3:できる
野球やサッカーのようなスポーツ、ピアノやギターといった楽器もそうですが「わかる」と「できる」は別物です。ギターを例に考えてみましょう。6本の弦を左手で抑えて、右手で弦を弾けば音が鳴る、というのは多くの人がわかります。またCコードやGコードといったコード進行について理解のある方もいるでしょう。しかし、当たり前のことですが、ギターの弾き方はわかったとしても、必ずしも上手にギターが弾けるというわけではありません。
プログラミングの世界においても同じで「わかる」と「できる」は大きく違います。プログラムの「わかる」人はコミュニケーションに参加することはできますが、コンピュータに向き合ってプログラミングできるとは限りません。
「わかる」から「できる」の段階へステップアップするには実践練習しかありません。つまり、コンピュータに向き合って、キーボードをタイプしてプログラミングする時間を作らなければなりません。「できる」ようになるためには疲れやストレスを伴う反復作業が必要なのです。これは楽器やスポーツの習得と同じです。繰り返しますが大事なのは反復練習です。プログラミングの習得の早い人の多くは、学んだことを丁寧に復習する人です。
「僕はスポーツの練習じゃなくて”武井壮を動かす練習”をしている」
武井壮さんの「僕はスポーツの練習じゃなくて”武井壮を動かす練習”をしている」という話があります。
プログラミングも同じで、頭の中でイメージしていることと、実際に体を使って表現することの間には乖離があって、それを埋めるためには質の良い練習をしないといけません。
「1万回のキックを1度だけ練習したものを恐れないが、ひとつのキックを1万回練習したものを恐れる」
ブルース・リーの名言も引用しておきます。
プログラミングの反復練習は丁寧に時間をかけてやりましょう。練習の前にコーヒーを準備しておくくらいの余裕があると良いかもしれません。
ブルームの法則
教育の世界には「ブルーム分類学」というものがあります。
ブルームの6分類法とは、技術を人間が習得するときの、人間の発達段階と、各段階における学習目標を示したものです。レベルの低い方から、記憶、理解、応用、分析、評価、創造、と続きますが、基本的に学習は、この順序で、各段階の目標をクリアしながら進めていかなくてはいけません。
ブルーム分類学では6つのレベルで学習目標を分類しています。
- 記憶
- 理解
- 応用
- 分析
- 評価
- 創造
個人的にはこの分類はよくできている(凄い)と思っています。ただ初見だと、難解に感じるので、6段階の上位3つ(分析、評価、創造)はひとまず置いておいて、最初の3つ(記憶、理解、応用)だけに絞って学習目標を考えるとわかりやすいです。
プログラミング習得の法則
まとめです。プログラミング習得の法則は3つのステップを踏みます。ブルームの分類も添えておきましょう。
- 覚える(=記憶)
- わかる(=理解)
- できる(=応用)
各ステップでの具体的な学習方法を織り交ぜると次のようになります。
- 覚える(記憶)
- 読む、聞くといったインプット作業
- わかる(理解)
- 自分の言葉でアウトプットする練習
- できる(応用)
- 手を動かしてアウトプットする練習
本を読んでいるだけではプログラミングはできるようになりません。学んだことを言葉やコードにしてアウトプットする習慣を身につけましょう。
そのためにはGitHubのようなサービスを上手く使えるようになるといいですよ。