LoginSignup
24
19

More than 3 years have passed since last update.

プログラミングの勉強方法として写経は非効率?

Last updated at Posted at 2020-08-02

はじめに

プログラミングの学習の進め方として写経があります。写経での学習方法に対しては、かなり非効率だという批判がありますが私としてはそうでは無いのではと思っており写経での学習もしています。

この投稿では写経での学習のポイントを私なりにまとめてみました。

写経学習のポイント

【大前提】バランスが大事。写経だけしても当然NG。アプリケーションを作ることを目標にしよう。

世の中何事も中庸が大切です。

エンジニアリングは世に役立つものを作ることが本質なので、まずは作りたいアプリケーションを作り出してしまい、つまずいた部分を逐次調べながら学ぶことも非常に重要だと思います。

しかし、体系的に学ぶこと(良質な書籍のコードの写経は体系的に学ぶための良い方法の1つだと思っています)も重要です。

単純な例で、Pythonにて1から9までの奇数のみを持つリストを作りたいとき、予備知識の無い初心者が1つずつ調べながら書くと以下のようなコードになるかもしれません。

>>> l = []
>>> for i in range(10):
...   if i % 2 == 1:
...     l.append(i)
>>> l
[1, 3, 5, 7, 9]

しかしrangeの仕様と内包表記を学習していれば下記のように1行で済むことを、逐次なやり方では知らずに進めてしまうことにもなり得ます。

>>> l = [i for i in range(1, 10, 2)]
>>> l
[1, 3, 5, 7, 9]

学習済みの箇所はコピペしよう

既に自分が十分に理解している箇所に関しては積極的にコピペして当然問題無いと思います。学ぶことが目的なので学びにならない箇所をモクモクと書いてしまうのは時間の無駄でしょう。

脳死ではやらない

コードを写経するときは意味を頭で反芻しながらやりましょう。

例えば下記のコード(Rust)では、「chunksという変数を宣言。0からN_THREADSの整数をmap。mapのクロージャの中身はseries_rangeから...」のように意味を考えながらやってみましょう。

let chunks = (0..N_THREADS).map(|ii| series_range.clone().skip(ii).step_by(N_THREADS)); |

"実験"もしながら理解を深めよう

上記のように考えながら進めると、写経対象のコードに対して疑問が浮かぶときがあります。

このXXの箇所をYYに置き換えたらどうなるんだろう?

などと思ったらやってみましょう。

以下の例では、私は写経対象コードにあるmove予約語を消すとどうなるか気になったので試してみて、その結果をコメント欄に書いて保存しました。

    .map(|vv| std::thread::spawn(move || {
    // .map(|vv| std::thread::spawn(|| { // moveを消すとコンパイルエラーになる。READMEに詳細を記載した。

得た知識をコードのコメントとして残そう

上記のように自分なりに新しく理解したことはコメントとして書いてみると良いと思っています。

    // ①
    // (①の説明) series_rangeをN_THREADS個に分割する。it.skip(ii)はitの先頭からii個をスキップする。
    // これにより、series_range.clone().skip(0), series_range.clone().skip(1), series_range.clone().skip(2) の3つができる
    // it.step_by(N_THREADS)はitからN_THREADS個ごとに取り出す。
    // https://doc.rust-lang.org/std/iter/trait.Iterator.html
    // の公式ドキュメントで詳細を参照できる。
    // 結果、chunks = [[0,3,6,...], [1,4,7,...], [2,5,8,...]]; が得られる。
    // ただし、mapは遅延処理なので、この段階では評価されない。
    // このmap内のクロージャは②の最後にあるcollectが呼ばれた際に、②にある他のmapとあわせて評価される。
    // series_rangeはcloneする。cloneをしないと、map内のクロージャにあるseries_rangeに所有権が移動し、
    // ii:1のときの後続で失敗してしまう。
    let chunks = (0..N_THREADS)
        .map(|ii| series_range.clone().skip(ii).step_by(N_THREADS));

写経したコードは自分の引き出しとしてすぐに取り出せるようにしておこう

私は写経したコードは自分のGitHubレポジトリにあげています。そうすると、キーワードに対して検索ができますし、プライベートでも職場でもすぐに参照することができます。

24
19
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
24
19