(provisional)

データサイエンティストになるためのあれこれ

【100回読み】リーダブルコード(#005)

どうも!
ryotaです!

「リーダブルコード」の100回読み、本日は5回目です!

今日は月曜日ということもあって、
新しくコードを追加していくというよりは
先週自分が書いたコードを一度整理するための時間を多くとりました。

リーダブルコードを読んでいるおかげで、
自分のコードをかなり客観的に見るクセがついてきたと思います。

今日特に意識したこととしては、

・クラスや関数に飛ばすのはいいが、
 飛ばす頻度を下げることができないか、
 また、飛ばすにしてもわかりやすくできないか
・変数や関数の名前をわかりやすくし、
 コメントがなくても理解しやすいコードにできないか

の2点でした。


この観点から自分のコードを見てみると、
流れがわかりにくいし、
変数や関数の名前もシンプルすぎて、
解釈の幅が広すぎたので
そのあたりを徹底的に改善していきました。

例えばよくやってしまいがちなのが、
ファイルのパスを
「pass」
という変数名で表したり、
そのパスを得るための関数を
「get()」
という名前で表したり、
ということです。

その名前を決めた時は完全に理解しているので
問題はないように思えますが、
数日経ってからその名前を見たときに、
または別の誰かが見たときに、
その変数や関数を見てすぐ理解できるとは限らないですよね。

ですのでパッと見てわかりやすく修正する必要がありました。

例えば、
「pass」を
「configFilePass」にするとか、
「get()」を
「getConfigFilePass」にするとか、
そういった工夫を追加することで、
コードとしては長くなるけど理解は速くなる、
ということが実現できます。

ちょっと英語の勉強にもなりますしね(笑)

英語の文章を読むみたいにコードを読むことができたら、
かなり理解が速くなるんじゃないかな?と気づきました。

なので、普段からこういった名前の付け方を意識するだけでも、
開発のスピードは上がりそうですね。
明日からも気を付けたいと思います!

名前の付け方、ぜひ意識しみてくださいね!

【100回読み】リーダブルコード(#004)

どうも!
ryotaです!

「リーダブルコード」の100回読み、本日は4回目です!

いやー同じ本を4回も読むって今までなかったんじゃないですかねー。
教科書とか問題集とかそういったものを除いて。
さらっと自己新記録を更新したような気がします。

さて、リーダブルコードで書かれていることを意識しながら仕事をしているのですが、
「ちゃんとロジックを追いかけることができていますか?」
ということについて書いてみたいと思います。

プログラミングとはデータ構造とアルゴリズムの組み合わせである、
ということが基本にあるのですが、
自分のイメージした通りに、データを動かすことができているのか?
ということが大切なんですよね。

昨日、自分が書いたコードを見直していたときに発見したんですが、
不必要なループ処理があったんです。
しかも処理のボリュームとしては結構大きい。

ざっくり言うと、
ループi(エクセルの1行目~最終行)に対して
ループj(あるファイルの文字列を1つ目~最後までリストに格納する)ということをしていたわけです。

で、このループjの処理は
あるファイルの文字列を1つ目~最後までリストに格納する、ということなんですが、
毎回する必要はなくて、そのプログラムの中で1回すればいいはずのものなんですよね。

それやのにエクセルの行ごとにやってしまっている…

これは非常に無駄過ぎる。
なんでこんなことになったんやろ…
と思い返してみれば、
最初はエクセルの行数に対してループ処理をしていなかったんですね。
つまりループiを作っていなかった。
まず、エクセルの1行目だけで、イメージした処理ができるかどうかを試したんですよね。

なので、
・エクセルの1行目に対して
・リストをループ処理によって作る
という流れになった。

で、それがうまくいったので、
「じゃあエクセルを最終行まで実行させる」
という流れになり、そこをループさせることによって
・エクセル1行ごとにリストを作る
ということになってしまったわけです。


まぁ詳細設計をせずに作りながら考えているので起こり得ることだったと思うのですが、
この問題点としては

「ロジックの流れを頭の中でイメージできていない」

ということなんですよね。

もちろんひとつひとつ書き出しながら丁寧にやれば防ぐことができたかもしれませんが、
僕にはそれができておりませんでした…


リーダブルコードを読んでから
「全体を小さく分解する」
ということを学び、
分解する中で無駄なループを発見した、
というわけなんです。

大きなかたまりの中では気づけなかったんですよね。

で、かたまりを分解して小さくすると何がいいかって、
今回の様にロジックをしっかりイメージしながら追いかけることができる、
ということだと思うんです。

特にループ処理や、メソッドや関数などであっちこっち飛ぶ場合に、
かたまりが大きいとどこまで進んだかイメージしにくくなってしまうんですよね。

なので、特にプログラミング経験が浅いうちは、
行数が多くなってもいいのでわかりやすい単位で分割すること、
そしてそれを実行したときにどういった処理になるのか、
ロジックを把握しながら書くこと、
を意識するととても読みやすく動きもスムーズなプログラムになるんじゃないでしょうか。


ということで「分割+流れ把握」を意識しながら今後も書いていこうと思います。

ぜひ参考にしてみてください~!

【100回読み】リーダブルコード(#003)

どうも!
ryotaです!

「リーダブルコード」の100回読み、本日は3回目です!

今日はリーダブルコードの中にある
「鍵となる考え方」
「アドバイス
「まとめ」
を見てから仕事をしてみました。

で、今の仕事であるツールを作っているのですが、
ちょっと行き詰まってまして、
データの動きが把握できないぐらいコードが冗長になってしまっていたんですね。

自分がイメージした動きを全くしてくれなくなり、
どこをどう改善していいのかわからない…
改善してみても思ったような動きをしてくれない…

そんな繰り返しでドツボにハマってました。

しかし、リーダブルコードの中に書いてあったある考え方を取り入れてみると、
みるみるうちに問題が解決していったんです。

それは、

「巨大な式は飲み込みやすい大きさに分割する。」

というアドバイス


僕の中では、
「ちゃんとロジック通りなのであれば、多少は式が長くなっても問題ない」
とか、
「何行になっても理解できていれば大丈夫」
というような考え方になっていたんですね。

しかしその結果、みるみるうちにコードが積み重なり、
もはや自分で書いたにも関わらず

「あれ、ここって何でこんな書き方をしたんやっけ?」
「この動きってどう繋がってるんやっけ?」
と彷徨うことに。

それが原因でハマってたわけですね。


それを
「巨大な式は飲み込みやすい大きさに分割する。」
というアドバイスをもとに、小さく分解していく、
更には、式だけではなくコードのブロックも分解していく、
と決めました。

他の人はどれぐらいのボリュームで分解しているんやろか?
と気になったので、ちょっとGitHubを覗いてみることに。
(実はGitHubで人のソースを見る機会をあまり作れてなかった笑)

そこで、自分にとっては衝撃的な光景が…


それは、

「たった16行のために1つのファイルを作っている」

という事実だったんです。


僕はなぜか、
「できるだけ多くのコードを1つのファイルに盛り込む」
という考え方をしてました。

なのでコードが多くなりすぎてしまい、
データの流れが把握できなかったんですね。


で、

「たった16行のために1つのファイルを作ってもいいんや!」

と衝撃を受けたことで、自分の中の(勝手な)価値観が崩れて、
そこからは自分が書いたコードを分解することに没頭しました。


その16行のまとまりを見た印象としては、

「ある1つのタスクを実行する最小単位」

というイメージだったんですね。


なので、自分が書いたコードも、
1つのタスクごとに分けよう、
と考えたわけです。


で、ひたすら分解し続けた結果、
あれだけハマっていた問題があっさり解決しました。

全体の流れを把握しながら、
タスクごとの動きも把握できたので、

「何が原因で詰まっていたのか」

ということを理解した瞬間、
解決策も思い浮かんでくるんです。

そこをちょっと改善したら思った通りの動きをしてくれる。

そこからは非常にスムーズにコーディングが進みました。

感覚としては、
生産性が2倍になった!
という印象です。


かの有名な哲学者、デカルト
「困難を分割せよ」
と言いました。

今までこの言葉を知ってはいましたが、
今回ほど仕事に活かせたな、と思ったことはありません。

これからは困ってから分割するのではなく、
常に分割することを意識しながら取り組んでみようと思います!

みなさんも困ったときは問題を分割してみてください、
めちゃくちゃ捗りますので!

【100回読み】リーダブルコード(#002)

どうも!
ryotaです!

「リーダブルコード」の100回読み、本日は2回目です!

今日、仕事でコーディングをしているときにリーダブルコードで学んだことを意識しながら書いてみました。
特に意識をしたのが、

  • 1. 文字を揃えて見やすくすること
  • 2. 式をわかりやすく分割すること

の3つです。


1つ目の「文字を揃えて見やすくすること」ですが、
例えば

・りんごの価格は100円
・みかんの価格は150円
・バナナの価格は200円

を変数を使って表現したいとします。

C#ですと

int apple_price = 100;
int orange_price = 150;
int banana_price = 200;

という書き方ですね。

それぞれの式を見てみると、変数の文字数が違うため、
"="から後ろの文字が、ズレていることがわかるかと思います。

まぁこれぐらいのズレ具合ですとそのままでもいいかもしれませんが、

int apple_price = 100;
int orange_price = 150;
int banana_price = 200;
int grapefruit_price = 250;

みたいに少し長い変数が入ってきてしまうと、
パッと見たときに見にくくなってしまうんですよね。

そこで、

int apple_price       = 100;
int orange_price      = 150;
int banana_price      = 200;
int grapefruit_price  = 250;

と縦を揃えることで、パッと見たときの見やすさが変わりますね。

ちなみに、ブログなので若干ズレてますが、
エディタだときっちり揃いますのでぜひ試してみてください。


次に、2つ目の「式をわかりやすく分割すること」です。

今までは「行数は少ない方がいい」と考えてコーディングをしていましたが、
リーダブルコードでは「行数が多いか少ないかよりも、理解しやすいかどうかの方が大切」という考え方があります。

例えば、

if ( fruits_price_list[0].ToString() == 100)

と条件式を書くこともできますが、
よりわかりやすくするなら

string fruit_price = fruits_price_list[0].ToString();
if ( fruit_price == 100)

とすることによって、条件式を見たときに感覚的にどのような条件なのかを把握することができます。

行数としては2行になってしまいますが、
「フルーツの価格が100円だったら」
と、英語を日本語に翻訳する感覚に近い状態でコードを読めるようになっていますよね。

こうした工夫をすることで、
他人が見ても理解しやすいコーディングができる、ということです。

このように、今日は
「感覚的にどうわかりやすくするのか」
ということを意識してみました!

ぜひ参考にしてみてください^^

【100回読み】リーダブルコード(#001)

どうも!
ryotaです!

最近読書に対する取り組み方を変えてまして、
今まで僕は
「100冊の本を1回読む」
という多読タイプでした。

でも色々と勉強法を研究してみると、
そういった多読もいいんですが特に新しいことを学ぶときは
「1冊の本を100回読む」
という勉強の仕方もあるということを知りました。

個人的にすごく斬新的な考え方やな~と思いまして、
その勉強法を取り入れてみることにしました!

ということで、
「同じ本を100回読む」
ということと、
「毎回学んだことや気づいたことを書く」
ということをやってみたいと思います!


なので、書評というよりは僕の学び・気づきの記録ですので、
そのつもりで読んでいただければと思います!


さて、記念すべき1冊目の本は
「リーダブルコード」
です!

これはプログラマーなら絶対読むべし!と言われている(らしい)本ですね。

僕は2018年7月からプログラマーになったばかりで、
しかも大学で勉強したりスクールで学んだり、といったことをせず、
基本的に本を読んで独学でやってきているので、
どうしても勉強する内容が偏ってしまったり、
基本がおろそかになって
「ひとまず動けばいいや」
みたいなことになりがちです。

もちろん自分なりにアンテナを広げているつもりではいるんですが、
やっぱり基本や王道が何なのか?ということは既に経験している人から聞いて、
そこから学ぶことが大切ですね!

この「リーダブルコード」も、色んなプログラマーの方が紹介してたり、
Twitterきっかけでやり取りすることもある、
さく@CF7期生(@fulong_yuri18)さんの紹介で読んでみることにしました!



この本で何度も繰り返し言われていることは、
「客観的に見て、最速で理解されやすいようなコードを書け!」
ということです。

その具体的な方法や考え方がひたすら書かれているな、
という印象です。

客観的に見て、って意外と難しいんですよね。
僕がコードを書いていてよくやってしまいがちな「客観的でない」コーディングは、

・「今」はわかる
 →「明日」もわかるかどうかは不明。

・「自分」はわかる
 →「他人」もわかるかどうかは不明。

というものです。

つまり、
「今の自分」はわかるけど、
「明日の自分」や「他人」はわからない、
というものです。

もちろん、自分一人で短期的に開発していればまだそれでもいいかもしれませんが、
中長期的に手掛けたり、複数人で開発するうえではそんなコードではダメですよね。

なので、
・数日ぶりにこのコードを自分が見ても理解しやすいのか?
・まったく内容を知らない他人が見ても理解しやすいのか?
といった視点で自分のコードを見ることで、
わかりやすいプログラムを書くことができるのです。


とくに変数やメソッド、クラス名などを自分で決めるときには、
誰がどう見ても解釈がずれないような書き方を意識してみましょう。

get()というメソッドは、何をgetするのかわかりにくい。
int numって、たぶん何らかの番号なんやろうけど…
return resultって、スコープが小さければそれでいいかもやけど、何度も出てくると感覚的にわかりにくいよな…

というように、
「ツッコミどころ」
をどんどんなくしていく感覚で自分のコードを見ていけばいいんじゃないかな、
と感じました!


あと、読み進んでいて気づいたんですが、
この本はプログラミング力を高める本というよりは、
国語力を高める本ですね。

文章の書き方、コピーライティングを学んだことがある人にとっては、
今まで学んだことのプログラミング版、といった印象を持つんじゃないでしょうか。

僕はもともと文章を書くことが好きですし、
コピーライティングをかじったこともあるので、
非常に読みやすかったです。

「プログラミングをするときもコピーライティングを意識すればいいのか!」
といった気づきもあったので、
どちらも経験がある人はぜひ意識してみてくださいね!

では今回のまとめはこの辺で。
明日も読んで学びや気づきをまとめていきます!

【C#】別のクラスに値を渡す

Visual C# 2017で別のクラスに値を渡すことができたので簡単にまとめたいと思います。

こちらの記事を参考にしました!)

やりたいこととしては、

  • 1. Form1にテキストボックス(T1)とボタン(B1)がある。
  • 2. Form2にテキストボックス(T2)とボタン(B2)がある。
  • 3. B1を開くとForm2が開く。
  • 4. B2を押すとT2のテキストがT1に反映される。

こんな感じです!

そのコードは以下の通り。

まずはForm1.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            Form2 f = new Form2();
            string recieveText = f.ShowMiniForm();
            textBox1.Text = recieveText;
        }
    }
}


次にForm2.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApp1
{
    public partial class Form2 : Form
    {
        public string returnText;

        public Form2()
        {
            InitializeComponent();
        }

        public string ShowMiniForm()
        {
            Form2 frm2 = new Form2();
            frm2.ShowDialog();
            string receiveText = frm2.returnText;
            frm2.Dispose();
            return receiveText;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            this.returnText = textBox1.Text;
            this.Close();
        }
    }
}


ざっくり説明します。

Form2 f = new Form2();

Form1でボタンをクリックすると、Form2のインスタンスを生成します。

string recieveText = f.ShowMiniForm();

Form2のShowMiniFormメソッドへ。
その戻り値がrecieveTextへ格納されます。

textBox1.Text = recieveText;

格納されたrecieveTextの値をテキストボックスに表示します。

ここまでがForm1です。


Form2の

public partial class Form2 : Form

のすぐ下にある

public string returnText;

は、ShowMiniFormメソッドとボタンをクリックしたときのイベントとの間で、
returnTextという変数をやり取りしたいのでここに記入してます。


ではShowMiniFormメソッドでは何をしてるかというと

Form2 frm2 = new Form2();

Form2のインスタンスを生成します。

frm2.ShowDialog();

ダイアログを表示します。

string receiveText = frm2.returnText;

returnTextをreceiveTextへ格納します。
returnTextはあとで出てきますので少々お待ちを。

frm2.Dispose();

リソースを解放します。
「今まで使用中だったけど、もう使っていいよー」
ってことかな?
ちょっと理解があいまいです。

return receiveText;

このメソッドの戻り値としてreceiveTextを返します。

ここまでがShowMiniFormメソッドです。


で、Form2のボタンをクリックするとこんな感じ。

this.returnText = textBox1.Text;

テキストボックスの値をreturnTextへ代入。

this.Close();

このクラス(表示されているダイアログのこと)を閉じる。


ということで、

  • Form1でボタンをクリックするとShowMiniFormメソッドによってダイアログが開かれる。
  • ダイアログの(Form2の)テキストボックスに入ってる値を、receiveTextっていう変数に代入する。
  • Form2のボタンを押すと、そのreceiveTextがForm1にいってテキストボックスに反映される。

となります。


これで別のクラスに値を渡すことができました!
「もっとこうした方がいいで!」
というのがあればぜひ教えてくださいー!

【C#】System.InvalidOperationException: XmlReader は、型 None のノードではなく型 Element のノード上に存在する必要があります。

Visual C# 2017で

  • 1. 起動したらJSONファイルを読み込む
  • 2. ボタンを押すと処理Aが実行される
  • 3. 他のコレクションで値を変える
  • 4. 再度ボタンを押して処理Aを実行させる

ということがしたいのですが、4. の際に以下エラーが出ました。

System.InvalidOperationException: XmlReader は、型 None のノードではなく型 Element のノード上に存在する必要があります。

で、エラーのあった個所を見てみると

ファイル名:Dynamicjson.cs

該当コード:

        public static dynamic Parse(string json, Encoding encoding)
        {
            using (var reader = JsonReaderWriterFactory.CreateJsonReader(encoding.GetBytes(json), XmlDictionaryReaderQuotas.Max))
            {
                return ToValue(XElement.Load(reader));
            }
        }

でした。


自分が書いたコードをよく見てみると、
JSONファイルを開くためのコードを「画面を起動したとき」に処理されるようになってました。
「ボタンを押したとき」に開いてなかったんですね。
そりゃ怒られるわ(笑)

ということで、JSONファイルを開くコードを、
ボタンを押すイベントハンドラー内に移動して解決!