ソースコードを見やすくしよう!リファクタリング②

こんにちは~。

MQLをマスターしたくて寝る時は加湿器を付ける(無意味)りょうです。

今回は前回のリファクタリングの続きを行います!

りょう

愚かなコードを見ていただきます

TOC

不要なif文に要注意! 深い入れ子は自分を苦しめる!

今回リファクタリングするコードはこちら↓。決済をする部分のコードです。

if( OrdersTotal() > 0 ) {
   for( int i = OrdersTotal() - 1; i >= 0; i--) {
      if( OrderSelect ( i, SELECT_BY_POS )) {
//ロングの時、パーフェクトオーダー終了で決済する
         if( OrderType() == OP_BUY ) {
            if( PerfectOrderIncrease ( smashort, smamiddle, smalong ) == false ) {
               int result = OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), Slippage, clrRed );
               if(result < 0) {
                  Print("注文に失敗しました");
               } else {
                  bool orderSelectResult = OrderSelect (result, SELECT_BY_TICKET);
                  Print ("注文に成功しました。決済価格は " + (string)OrderClosePrice() + " です。");
               }
            }
//ショートの時、パーフェクトオーダー終了で決済する
         } else if (OrderType() == OP_SELL) {
            if( PerfectOrderFalling ( smashort, smamiddle, smalong ) == false ) {
               int result = OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), Slippage, clrRed );
               if(result < 0) {
                  Print("注文に失敗しました");
               } else {
                  bool orderSelectResult = OrderSelect(result, SELECT_BY_TICKET);
                  Print("注文に成功しました。決済価格は " + (string)OrderClosePrice() + "です。");
               }
            }
         }
      }
   }
}

プログラミングスキルが高い人が見たら一目で無駄なところが多いと思うかもしれません。

にゃんぽこ

下の6連続の『 } 』が気になるのう・・・

まず1行目と2行目に関してです。
1行目の『 if( OrdersTotal() > 0 )』は『1つでもエントリー状態であれば決済判定』という意味です。
2行目の『for( int i = OrdersTotal() – 1; i >= 0; i–)』は『 OrdersTotal() が0になるまでループし続ける』という意味で、つまり『 OrdersTotal() が0であれば実行されない』という意味です。

なので、1行目の『 if( OrdersTotal() > 0 ) 』は必要ないのです。

りょう

つまり・・・僕は・・・

にゃんぽこ

そう・・・必要ないコードをせっせと考えて作っていたんだぜ

りょう

ガーン

続いて5,6行目です。

if( OrderType() == OP_BUY ) {
   if( PerfectOrderIncrease ( smashort, smamiddle, smalong ) == false ) {


↑この2行のコードなのですが、もしif文の形式が

if( 条件1 ) {
   if( 条件2 ) {

  }else{

  }
 }


↑のようにif文の中にさらに分岐があればこの形式で良いのですが、今回の場合は

if( 条件1 ) {
   if( 条件2 ) {

  }
 }


↑このように分岐がありません。なのでif文の中にif文をつくる必要がなく

if( 条件1 && 条件2 ) {

 }


↑これでよいのです。なのでまとめます。

りょう

あーそうだった・・・

ムゥ

初心者はifで囲いがちにゃ

にゃんぽこ

ほんっとにイフイフイフイフうるさいわよあーた

りょう

うぅ・・・すいません・・・

また、16,17行目の『//ショートの時、パーフェクトオーダー終了で決済する』の下にある

} else if (OrderType() == OP_SELL) {
   if( PerfectOrderFalling ( smashort, smamiddle, smalong ) == false ) {


↑こちらに関しても同じ内容なのでまとめておきます。

このようにif文の中にif文を入れることを『入れ子(英語ではネスト)』と言います。

入れ子のし過ぎはコードがとても見づらくなり、のちの自分をとても苦しめます。注意しましょう!

にゃんぽこ

おいお前ちょっと待て!入れ子やってたな!

りょう

そんな振り込め詐欺の一員みたいに言わないでください!
出し子じゃないですよ!

ムゥ

タイホにゃ!

りょう

待ってください!僕は詐欺なんかしてません!入れ子をしたんです!
ただプログラミングが超絶下手くそなだけなんです!

DRY『重複は悪』

つづいて、それ以降のコードです↓。

    int result = OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), Slippage, clrRed );
    if(result < 0) {
       Print("注文に失敗しました");
     } else {
        bool orderSelectResult = OrderSelect (result, SELECT_BY_TICKET);
        Print ("注文に成功しました。決済価格は " + (string)OrderClosePrice() + " です。");
     }
  }
//ショートの時、パーフェクトオーダー終了で決済する
} else if (OrderType() == OP_SELL && PerfectOrderFalling ( smashort, smamiddle, smalong ) == false ) {
       int result = OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), Slippage, clrRed );
       if(result < 0) {
          Print("注文に失敗しました");
        } else {
           bool orderSelectResult = OrderSelect(result, SELECT_BY_TICKET);
           Print("注文に成功しました。決済価格は " + (string)OrderClosePrice() + "です。");


この中で、先ほど修正した10行目以外は内容が完全に重複しています。

プログラミングの世界には『DRY(Don’t repeat yourself)』という言葉があります。
日本語では『重複は悪』と言います。

プログラミングでは同じ命令のコードを重ねて書くことはバグの原因となり、また人間が見直す時も非常に見づらく、百害あって一利なしなのです。

にゃんぽこ

重複していたら「ダメだっ!」と思うのだ!

今回の場合は実行内容が全く一緒なので、

if( 条件1 || 条件2 ){
    実行
}


↑このようなシンプルな形にできます。

//利益確定の条件(パーフェクトオーダー終了で決済)
   for( int i = OrdersTotal() - 1; i >= 0; i--) {
      if( OrderSelect ( i, SELECT_BY_POS )) {
         if(( OrderType() == OP_BUY && PerfectOrderIncrease ( smashort, smamiddle, smalong ) == false )          //買いの場合
                || (OrderType() == OP_SELL && PerfectOrderFalling ( smashort, smamiddle, smalong ) == false )){  //売りの場合
            int result = OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), Slippage, clrRed );
               if(result < 0) {
                  Print("注文に失敗しました");
               } else {
                  bool orderSelectResult = OrderSelect (result, SELECT_BY_TICKET);
                  Print ("注文に成功しました。決済価格は " + (string)OrderClosePrice() + " です。");
               }
            }
        }
    }


ここまで簡潔な形にできました!!

ムゥ

とてもスッキリしたにゃ~

最初と比べてかなりスッキリしましたが、もう少し簡潔に書いていきます。

仕上げ & まとめ

if( 条件1 == false ){

}


↑この形は

if( !条件1 ){

}


↑このような形で書くことができます。

にゃんぽこ

条件の前に『 ! 』を付けたら『falseの時』という意味になるんだよ

にゃんぽこ

なにもつけないと『trueの時』っていう意味だよ

//利益確定の条件(パーフェクトオーダー終了で決済)
   for( int i = OrdersTotal() - 1; i >= 0; i--) {
      if( OrderSelect ( i, SELECT_BY_POS )) {
         if(( OrderType() == OP_BUY && !PerfectOrderIncrease ( smashort, smamiddle, smalong ) )           //買いの場合
                || (OrderType() == OP_SELL && !PerfectOrderFalling ( smashort, smamiddle, smalong ))){    //売りの場合
            int result = OrderClose( OrderTicket(), OrderLots(), OrderClosePrice(), Slippage, clrRed );
               if(result < 0) {
                  Print("注文に失敗しました");
               } else {
                  bool orderSelectResult = OrderSelect (result, SELECT_BY_TICKET);
                  Print ("注文に成功しました。決済価格は " + (string)OrderClosePrice() + " です。");
               }
            }
        }
    }


↑このようになりました。

『 ! 』に関しては人によっては「『 == false 』のほうが見やすくて好き!」という人がいるかもしれません。

ムゥ

自分が使いやすい方を使うとよいにゃ~

ということで、リファクタリングでかなりコードをスッキリさせることができました!

今回のまとめは

①入れ子(ネスト)を深くしすぎるのは要注意!
②DRY (Don’t repeat yourself) 重複は悪!

というところでしょうか!

僕もまだまだ未熟なのでこれからも気づかないうちにたくさんミスをしてしまうと思います・・・。

作業を進めていくとどんどん視野が狭くなっていって

『作業1』が終わる

『作業2』を作り始める

『作業2』の事しか考えず『作業1とまとめられる』事を考えていない

といった状況になっていってしまいます・・・。

りょう

そういった悪循環にならないように気づいたらすぐに改善していけるように頑張ります~

にゃんぽこ

頑張るのだ~

TOC
閉じる