独学Ruby -基礎③-

引き続き、Rubyの基礎その3。

tanoshiiruby.github.io

Contents


メソッド

  • インスタンスメソッド
  • クラスメソッド
  • 関数的メソッド ... print文とか
# インスタンスメソッドの例

array = "10, 20, 30, 40"
print array,"\n"
array = "10, 20, 30, 40".split(",")
print array,"\n"
print array[0], "-",array[1] , "-",array[2] , "-",array[3], "\n"

# クラスメソッドの例
# 新しい配列を作成
a = Array.new

メソッドの定義

メソッド名にはアルファベット、数字、アンダースコアを使うことができる。

数字で始めるのはNG。

@myNumber = 0

def GetMyNumber()
    return @myNumber
end

def SetMyNumber(number=100)
    @myNumber = number
end

呼び出し元

require_relative "mymethod.rb"

my_number = GetMyNumber()
print my_number,"\n"

SetMyNumber(10)
my_number = GetMyNumber()
print my_number,"\n"

SetMyNumber()
my_number = GetMyNumber()
print my_number,"\n"

引数を省略したときにデフォルト値を設定することもできる。

複数の戻り値を返すことも可能

def GetValue()
    return 1, 2
end

results = Array.new
results = GetValue()
print results

クラス

オブジェクトが属しているクラスを知る

.classメソッド

ary = Array.new
p ary.class

str = "String"
p str.class

オブジェクトがクラスのインスタンスかどうかを知る

.instance_of_?(クラス名)

ary = Array.new
p ary.instance_of?(Array)
str = "String"
p str.instance_of?(String)

クラスの定義

class文

クラスを作るときの注意点

クラス名は必ず大文字で始めること。

# 時計クラス(スーパークラス)

class Clock
    # 定数
    Version = "1.0"
    
    # クラス変数
    @@name = "Clock"
    
    # インスタンス変数
    @current_time = Time.new        # 現在時刻で初期化
    
    # クラスメソッド
    def Clock.getVersion()
        return Version
    end
    
    def Clock.getName()
        return @@name
    end
    
    # newメソッドコール時に実行される
    def initialize(cur_time=Time.new)
        print "Clock Class Version is ", Version,"\n"
        @current_time = cur_time
    end
    
    # インスタンスメソッド
    def setTime(time)
        @current_time = time
    end
    
    def getTime()
        return @current_time
    end
    
    # アクセスメソッド
    def current_time
        return @current_time
    end
    
    def current_time=(time)
        @current_time = time
    end
    
end

initializeメソッドを定義すると、newメソッド時に実行される。

  • クラスメソッドの呼び出し
  • クラス内の定数の取得
  • インスタンス生成
  • インスタンスメソッドの呼び出し
  • アクセスメソッドの呼び出し
require_relative "clock"

# クラスメソッド
p Clock.getVersion()
p Clock.getName()

# 定数のGet
p Clock::Version

# インスタンス生成
clock = Clock.new()
current_time = clock.getTime()
p current_time

# インスタンスメソッドでSet/Get
clock.setTime(Time.local(2019,1,1,12,30,10,0))
current_time = clock.getTime()
p current_time

# アクセスメソッドでSet/Get
clock.current_time = Time.new()
p clock.current_time

クラスの拡張

たとえばStringクラスを定義し、メソッドを拡張してみる。

string.rb

class String
    def func()
        print "func method of String\n"
    end
end

ext_string.rb

class String
    def extFunc()
        print "extFunc of String(Extention)\n"
    end
end

str.rb(実行元)

require_relative "string"
require_relative "ext_string"

str = String.new
str.func()    # string.rbで定義
str.extFunc() # ext_string.rbで定義

メソッド呼び出しの制限

アクセス制限レベル 説明
public メソッドをインスタンスメソッドとして使えるように公開する
private メソッドをクラス内部でだけ使えるようにする
protected メソッドをクラス内部で使えるようにする
同一クラス内ではインスタンスメソッドとしても使える
# アクセス制限

class AccessTest
    def pubMethod
        print "called Public Method\n"
    end
    public :pubMethod
    
    def privateMethod
        print "called Private Method\n"
    end
    private :privateMethod
    
    def protectedMethod
        print "called Protected Method\n"
    end
    protected :protectedMethod
end
require_relative "access_test"

access_test_obj = AccessTest.new()

# インスタンスメソッドとして直接呼べる
access_test_obj.pubMethod()

# インスタンスメソッドとして直接呼べない
access_test_obj.privateMethod()   # Error

# インスタンスメソッドとして直接呼べない
access_test_obj.protectedMethod()  # Error

Protectedメソッドへのアクセス

# AccessTestクラスを継承する
require_relative "access_test"

class AccessSubTest < AccessTest
    def hoge
        privateMethod()
    end
end
require_relative "access_sub_test"

access_sub_test_obj = AccessSubTest.new()

access_sub_test_obj.hoge()

アクセス制限の記述方法

 上のようにpublic :メソッド名という形で書くこともできるが、

 次のようにするとまとめて同じアクセス制限にできる。

# アクセス制限

class AccessTest
    public     #これ以降のメソッドはPublic
    
    def pubMethod1
        print "called Public Method\n"
    end
    
    def pubMethod2
        print "called Public Method\n"
    end
    
    private     #これ以降のメソッドはPrivate
    
    def privateMethod1
        print "called Private Method\n"
    end
    
    def privateMethod2
        print "called Private Method\n"
    end
    
    protected     #これ以降のメソッドはProtected
    
    def protectedMethod1
        print "called Protected Method\n"
    end
    
    def protectedMethod2
        print "called Protected Method\n"
    end
end

クラスの継承

class クラス名 < スーパークラス名
    ...
end

すでに上のprotectedメソッドのアクセス確認で書いたけど。

# スーパークラス
class SuperClass
    def initialize()
        print "Create Super Class.\n"
    end
    
    def func1()
        print "func1 of SuperClass.\n"
    end
    
    def func2()
        print "func2 of SuperClass.\n"
    end
    
end
# サブクラス
require_relative "super_class"

class SubClass < SuperClass
    def initialize()
        print "Create SubClass.\n"
    end
    
    def func2()
        print "func2 of SubClass.\n"
    end
    
end
require_relative "sub_class"

obj1 = SuperClass.new()
obj2 = SubClass.new()

obj1.func1()
obj2.func1()

obj1.func2()
obj2.func2()

実行結果。

Create Super Class.
Create SubClass.
func1 of SuperClass.
func1 of SuperClass.
func2 of SuperClass.
func2 of SubClass.

以上、。

独学Ruby -基礎②-

引き続き、Rubyの基礎その2。

tanoshiiruby.github.io

Contents


オブジェクトと変数・定数

データを表現する基本単位(オブジェクト)。

  • 数値オブジェクト(Numeric)
  • 文字列オブジェクト(String)
  • 配列オブジェクト (Array)
  • ハッシュオブジェクト(Hash)
  • 正規表現オブジェクト(Regexp
  • ファイルオブジェクト(File) などなど

変数の種類

  • ローカル変数 ... 先頭がアルファベットの小文字か「_」で始まる
  • グローバル変数 ... 先頭が「$」で始まる
  • インスタンス変数 ... 先頭が「@」で始まる
  • クラス変数 ... 先頭が「@@」で始まる
  • 擬似変数 ... true, false, self, nil などの予約語

変数のスコープ確認

# グローバル変数
$globalVariable = 111

# ローカル変数
localVariable = 222

# sub.rb呼び出し
require_relative "sub"

p $globalVariable
p localVariable
#グローバル変数に代入
$globalVariable = 777

#ローカル変数に代入
localVariable = 555

globalVariableは111ではなく777となる。

localVariableは555ではなく222のまま。

定数

先頭がアルファベットの大文字で始まるもの

実際に定数宣言後に別の値を代入するとWarningが宣告される。

値は書き換わる。

scopetest.rb:17: warning: already initialized constant CONST_VARIABLE
scopetest.rb:14: warning: previous definition of CONST_VARIABLE was here

予約語

BEGIN

END など


条件判断

  • if
  • unless
  • case
number = ARGV[0].to_i

#-------------------------
# if文
#-------------------------
if number == 1
    print "number is 1.\n"
elsif number == 2
    print "number is 2.\n"
else
    print "number is ", number , "\n"
end

#-------------------------
# unless文
#-------------------------
unless (number == 1) || (number == 2)
    print "number is ", number , "\n"
else
    print "number is 1 or 2.\n"
end

#-------------------------
# case文
#-------------------------
case number
when 1 then
    print "number is 1.\n"
when 2 then
    print "number is 2.\n"
else
    print "number is ", number, ".\n"
end

# 複数の条件を指定することもできる
case number
when 1, 2 then
    print "number is 1 or 2.\n"
else
    print "number is ", number, ".\n"
end

# クラス判定
array = ["moji", 1, nil]
array.each do |obj|
    case obj
    when String
        print "obj is a String.\n"
    when Numeric
        print "obj is a Numeric.\n"
    else
        print "obj is someting.\n"
    end
end

if修飾子とunless修飾子

実行したい式の後ろに条件式を書ける。

number = ARGV[0].to_i

print "number is 0.\n"      if number == 0
print "number is not 0.\n"  if number != 0

繰り返し

  • 構文
  • メソッド
命令 構文 メソッド
times
for
while
until
each
loop

timesメソッド

2通りの書き方がある。

# timesメソッド

# 書き方1
3.times do
    print "loop.\n"
end

# 書き方2
3.times {
    print "loop.\n"
}

# 繰り返し回数を知る
3.times do |i|
    print "loop[", i, "].\n"
end

for文

#ループ回数を指定する方法
from_idx = 3
to_idx   =  5
for idx in from_idx..to_idx
    print idx,"\n"
end

#範囲オブジェクトでループ回数を指定する方法
array = [1, 2, 3]
for var in array
    print var,"\n"
end

while文

i = 1
while i < 3
    print i,"\n"
    i += 1
end

until文

i = 1
until i > 3
    print i,"\n"
    i += 1
end

eachメソッド

names = ["awk", "Perl", "Python", "Ruby"]
#書き方1
names.each do |name|
    print name, "\n"
end

#書き方2
names.each { |name|
    print name, "\n"
}

#書き方3
(1..5).each do |num|
    print num, "\n"
end

loopメソッド

無限ループにならないように繰り返しの制御を。

#loopメソッド + break

i = 0
loop do
    if i == 5 then
        break
    else
        i += 1
    end
    
    print i, "\n"
end

繰り返し制御

language = ["C", "C++", "Ruby", "Python", "Java"]
print language,"\n"

# break
language.each do |lang|
    case lang
    when /^C/ then
        print "C Series language =>", lang, "\n"
    when /Ruby/ then
        print "Ruby\n"
    else
        print "Other"
        break;
    end
end

print "\n---------------\n"

# next
language.each do |lang|
    if lang == "C++" then
        print "Skip C++\n"
        next
    end
    
    print lang,"\n"
end

print "\n---------------\n"

# redo
language.each do |lang|
    if lang == "C++" then
        print "C++ => C#\n"
        lang = "C#"
        redo
    end
    
    print lang,"\n"
end

以上。

独学Ruby -基礎①-

まずは基礎の基礎から。

tanoshiiruby.github.io

Contents

 ・配列(Array)  ・ハッシュとシンボル  ・正規表現(パターンマッチング)  ・コマンドライン  ・ファイルの読み込み



動作環境

paiza.io (https://paiza.io/ja/projects/new)

Ruby MSI Packages (https://www.artonx.org/data/asr/)


まずはRubyを使ってみる

ではさっそくRubyを動かしてみよう

まずはお決まりのHelloWorldから。どれも同じ出力結果。

print("Hello World\n")
print "Hello World\n"
print "Hello", " ", "World", "\n"
puts "Hello World\n"

文字列と数値を意識して出力してくれるpメソッド。

3puts "100"
puts 100

コメントを現す記号は#。行末までコメントになる。

# コメント

=beginと=endで囲まれた範囲もコメント。

=begin
コメント
コメント
=end

制御構造を分類すると、

  • 逐次処理
  • 条件判断 (if then end)
  • 繰り返し (while times)
  • 例外処理
my_weight_kg = 80
your_weight_kg = 70

# 条件判断
if my_weight_kg > your_weight_kg then
    print "私の体重のほうが重い"
else
    print "あなたの体重のほうが重い"
end

# 繰り返し
i = 1
while i <= 10
    print i, "\n"
    i = i + 1
end

10.times do
    print "A"
end

メソッドの作成について。

# メソッド定義
def hello
    print "Hello World\n"
end

# メソッド呼び出し
hello

自作したrubyファイル(.rb)を呼び出す

def hello
    print("Hello World\n")
end

hello.rbのhelloメソッドを呼び出すためにrequireメソッドを使うのだが、自作したrbファイルはrequire_relativeメソッドがよさそう。requireメソッドはPathが通っていないとダメっぽい。

require_relative "hello"
hello()

便利なオブジェクト

Rubyで書籍の購入リストを作ることを考えてみる。購入リストの項目は以下とする。

  • 購入日
  • 種別(コンピュータ書、ノンフィクション、小説など)
  • 書名
  • 著者名
  • 出版社
  • ISBN
  • 金額

例)

パラメータ名 値の例 データ型
購入日 2019年1月17日 日付
種別 コンピュータ書 文字列
書名 たのしいRuby 第3版 文字列
著者名 高橋征義、後藤裕蔵 文字列
出版社 Softbank Creative 文字列
ISBN 978-4-7973-5740-0 文字列
金額 2640 数値

配列(Array)

  • 生成
  • 取り出し
  • 代入
  • 繰り返し
# 空配列の生成
name = []
p name

# 初期値付き配列の生成
name = ["A", "B", "C"]
p name

# 配列からオブジェクトを取り出す
print("[0]=", name[0], "[1]=", name[1], "[2]=", name[2], "\n")

# オブジェクトの代入
name[0] = "D"
print("[0]=", name[0],"\n")

# 配列には異なるデータ型のオブジェクトを混ぜられる
mix = ["String", 1, "A", 2, "B"]
p mix

# 配列と繰り返し
mix.each do |var|
    print(var , "\n")
end

ハッシュ(Hash)とシンボル(Symbol)

  • 生成
  • 取り出し
  • 代入
  • 繰り返し
# ハッシュテーブルの生成]
hash_table = {:sym1 => 0, :sym2 => "string"}
p hash_table

# ハッシュテーブルからの取り出し
print("[0] = ", hash_table[:sym1], "\n")
print("[1] = ", hash_table[:sym2], "\n")

# ハッシュテーブルへの格納
hash_table[:sym1] = 1
hash_table[:sym2] = "index"
hash_table[:sym3] = "new"
print("[0] = ", hash_table[:sym1], "\n")
print("[1] = ", hash_table[:sym2], "\n")
print("[2] = ", hash_table[:sym3], "\n")

# データ型も変更可能
hash_table[:sym3] = 1
print("[2] = ", hash_table[:sym3], "\n")

# 繰り返し
hash_table.each do |symbol, var|
    print(symbol, "=", var, "\n")
end

正規表現

  • パターンマッチング (=~演算子)
    • マッチングに成功するとマッチした位置を返す
    • マッチングに失敗するとnilを返す
# パターンマッチング

# 先頭で一致
pos = /Ruby/ =~ "Ruby"
print(pos, "\n")

# 中間で一致
pos = /Ruby/ =~ "iRuby"
print(pos, "\n")

# 一致しない
pos = /Ruby/ =~ "rUBY"
print(pos, "\n")

nil(ニル)

  • オブジェクトが存在しないことを示す値

コマンドライン

コマンドライン引数ARGV[]。

print "1番目の引数:", ARGV[0], "\n"
print "2番目の引数:", ARGV[1], "\n"
print "3番目の引数:", ARGV[2], "\n"

文字列を数値に変換(to_iメソッド)

print ARGV[0], "\n"
num = ARGV[0].to_i
print num

ファイル読み込み

  • openメソッド
  • readメソッド
  • closeメソッド
  • getsメソッド

一度にテキストファイルをロードする

# ARGV[0] = FileName(*.txt)

# Case1
filename = ARGV[0]
file = open(filename)
text = file.read
print text
file.close

# Case2
filename = ARGV[0]
text = File.read(filename)
print text

# Case3
print File.read(ARGV[0])

一行ずつ読み込む

# ARGV[0] = FileName

filename = ARGV[0]
file = open(filename)

# 1行ずつ読み出す
while textline = file.gets
    print textline
end

file.close

特定パターンの行のみを出力する

# ARGV[0] is Pattern String
# ARGV[1] is File Name

pattern = Regexp.new(ARGV[0])
filename = ARGV[1]

file = open(filename)
while textline = file.gets
    if pattern =~ textline
        print textline
    end
end
file.close

utf-8

ruby -Ks スクリプトファイル名.rb

以上。

Python3.7.2 on Windows

ゼロから作るDeepLearning2を独学するためPythonをインストールしました。

www.oreilly.co.jp

 

本書で使用するプログラミング言語とライブラリは以下。

  • Python 3系

  • NumPy

  • Matplotlib

  • CuPy (オプション) ... 今回は使用しない

 

本書のサンプルコードは以下。

github.com

 

 

Python 3.7.2のインストール

 

以下のサイトを参考にします。

www.python.jp

 

Python 3.7.2 Windows 64Bit版  (2019/1/19 最新)をダウンロード。

https://www.python.org/ftp/python/3.7.2/python-3.7.2-amd64.exe

 (python-3.7.2-amd64.exe)

 

インストール確認は、コマンドプロンプトを開いて「python -V」を実行。

Python 3.7.2と表示されればOK。

 

 

ライブラリのインストール

  • NumPy

  • Matplotlib

コマンドプロンプトで以下を実行する。

> python -m pip install numpy

> python -m pip install matplotlib

これでOK。

 

ということで早速、独学スタート!

 

以上。

 

 

 

 

 

 

攻撃から工場を守る産業制御システム・セキュリティ

セキュリティベンダーのSymantecが工場向けにセキュリティソリューションを推し進めている。競合のトレンドマイクロマカフィーも同様。各社制御セキュリティに詳しくない現場にとって利用しやすいソリューションを提案している。(らしい)

 

monoist.atmarkit.co.jp

 

工場を狙う2つのベクトルとは・・・ (by Kunal Agarwal@Symantec)

次に、この攻撃ベクトルに対してSymantecが提案しているソリューションについて。

 


Symantecの提案するソリューション

 

USBスキャンクリーニングステーション

  • 工場で利用するPCはUSBスキャニングステーションでチェック済のUSBメモリだけを認識できるドライバを組み込む

 

データシート

https://www.symantec.com/content/dam/symantec/docs/data-sheets/usb-scanning-data-sheet.pdf

 

 

クリティカルシステムプロテクション(CSP)

  • エンドポイントおよび組み込みデバイスを守ることでIoT環境を保護するための軽量セキュリティクライアントソフト

  • 組み込み機器などに適用できように軽量化されている

  • 工場で稼働しているレガシーな端末を最新機器のようにネットワーク利用できる

 

www.symantec.com

 

データシート

https://www.symantec.com/content/dam/symantec/docs/data-sheets/embedded-security-critical-system-protection-en.pdf

 

どちらも現場の技術者の敷居を下げるため、シンプルさに重きを置いている。

 

 

Symantec Blogs

www.symantec.com

 

以上。

 

 

制御セキュリティがなぜアツいのか!?

今年度(2019)は制御セキュリティに関する話題を収集するためのアンテナを張ろうかと思う。今日はMONOistから「なぜ今、制御システムセキュリティがアツいのか?」という特集を紹介する。

 

monoist.atmarkit.co.jp

 

制御システムのセキュリティが注目を浴びている理由

  1. 制御システムを取り巻く環境の変化

  2. 制御システムを狙った攻撃(マルウェアの登場)

  3. 制御システムセキュリティに対する国レベルでの取り組み開始

何年か前にドイツのテクノロジー企業シーメンスのPLCが攻撃にあった。

確かそのときのマルウェアがStuxnet。イランの核施設の破壊も狙ったとか。

https://wired.jp/2012/06/04/confirmed-us-israel-created-stuxnet-lost-control-of-it/

 

この工場などの制御システムを狙ったマルウェアの登場で国レベルで対策が必要と考えられ始めた。工場の閉じた世界もIoTなどの普及に伴い外部のネットワークと密接に絡み始めた昨今、制御システムのセキュリティ対策が急務とされる所以である。

 

制御システムを取り巻く環境の変化

  1. 制御システム間の通信インタフェースのイーサネット

  2. 制御システムの汎用OS化(WindowsLinuxRTOS・・・)

かつてはRS232Cなどのシリアル通信インタフェースが一般的だったが、いまではイーサネットが当たり前になってきており、EtherNet/IP、EtherCATなどの通信規格も利用されている。工場のLAN化が進みセキュリティの面に配慮せざるを得なくなっている。また制御システムに汎用OSが使われることも増え、脆弱性を狙った攻撃に対しても防御しなければならなくなっている。

 

制御システムを狙った攻撃の登場

制御システムを狙った代表的なマルウェア

マルウェア 概要
Stuxnet インターネットまたはUSBメモリから感染し潜伏する。 感染したコンピュータに接続するとパンデミックを引き起こす。 イランの核施設を攻撃するためにアメリカとイスラエルが開発した。
Slammer SQLサーバ2000の不具合を利用して UDPポート1434に対して攻撃するワーム。
Zotob Windows2000にターゲットとし プラグ案とプレイ機能の脆弱性をついて侵入する。 自動的に再起動するなどの症状を引き起こす。
Conficker  

ConfickerのようなUSBメモリを介して感染するタイプのマルウェアが2008年頃から今もなお猛威を振るっているらしい。

こういった背景もあってトレンドマイクロなどの大手セキュリティソフトウェア会社はさまざまなセキュリティソリューションを提案している。

 

https://www.trendmicro.com/ja_jp/about/trendpark/es-smartfactory-expo-201803-01-01.html

 

制御システムセキュリティに対する国レベルの取り組み開始

2013年にオバマ大統領が重要インフラに対するサイバー攻撃に対処するように大統領令を発行。時を同じくして欧州でもセキュリティ強化をインフラ事業者に求めた。

では我が日本国はどうか・・・

https://www.jssec.org/dl/20180309_Hiroshi_itou.pdf

 

情報セキュリティの10大脅威

順位 脅威
1 標的型攻撃による情報流出
2 ランダムウェアによる被害
3 ビジネスメール詐欺
4 脆弱性対策情報の公開に伴い公知となる脆弱性の悪用増加
5 セキュリティ人材の不足
6 ウェブサービスからの個人情報の窃取
7 IoT機器の脆弱性の顕在化
8 内部不正による情報漏えいとそれに伴う業務停止
9 サービス妨害攻撃によるサービス停止
10 攻撃のビジネス化(アンダーグラウンドサービス)

 

経済産業省の取り組み

  • IPAが監査・監視

  • 産業分野別のセキュリティポリシーの設定、国際標準化

  • サイバーセキュリティガイドラインの策定

  • 重要インフラ事業者のリスク評価事業

  • 情報供給、初動対応支援体制の強化

  • 人材育成

  • 国際連携(アメリカ・欧州など)

 

これから

すでに「工場は閉じた世界だからセキュリティは大丈夫」という神話は崩れている。

制御システム技術者としてこの流れをどのように捉えるか。

制御システムセキュリティはすでにビジネス化しつつある。。。。

 

以上。

 

 

 

 

 

リーダブルコード

リーダブルコード

O'REILLY Japan

 

本書のテーマ

読みやすいコードを書くコツを会得しよう!

 

読みやすさの基本定理

コードは他の人または(数カ月後の自分)が最短時間で理解できるように書くべし!

 

表面上の改善

 

Check 鍵となる考え ポイント
名前に情報を詰め込む 明確な単語を選ぶ 汎用的な名前を避ける 抽象的な名前よりも具体的な名前を使う 接尾辞や接頭辞を使って情報を追加する 名前の長さを決める 名前のフォーマットで情報を伝える

 

  • 類語辞典を使って、より明確で正確な単語を探してみるべし

  • tmpという名前は生存期間が短い変数につけるべし

  • イテレータによく使うi, jなどを説明的な工夫を(club_i, members_i, users_i とか)

  • 変数名に単位を入れる (size_mbyte, max_kbps, delay_secとか)

  • 重要な属性を付与する (plaintext_pasword, html_utf8とか)

  • スコープが狭いなら短い変数名もOK

  • プロジェクト固有の省略形はNG

  • 意味が損なわれないなら不要な単語を削除 (ConvertToString→ToString)

  • 名前のフォーマットで情報を伝える

以下はGoogle社のあるプロジェクトチームで使われているフォーマット規約(らしい)

要するに、自分自身やチームで規約を守ろうということ。

クラス名:キャメルケース

ローカル変数:小文字をアンダースコアで区切る

メンバ:最後にアンダースコア

static const int kMaxOpenFiles = 100;
class LogReader {
   public:
   void OpenFile(string local_file);
   private:
   int offset_;
};

 

Check 鍵となる考え
他の意味と間違えられることはないか自問自答すべし
  • 限界値を含めるときはmin, maxを使う

  • 範囲を指定するときはfirst, lastを使う

  • 包含/排他的範囲にはbegin, endを使う

  • ブール値の名前 (is・has・can・shouldなど)

  • ブール変数名は肯定的にすべし

  • ユーザが期待するとおりに命名すべし (get関数は値をgetするだけであるべき)

 

 

Check 鍵となる考え ポイント
そのコードの見た目は美しいか 読み手がなれているパターンか? 一貫性のあるレイアウトか? 似ているコードは似ているように見せる 関連するコードをブロック化

見た目が美しいコードのほうが理解する時間は短縮される!

さっと流し読みできるのが理想。

  • 一貫性のある簡潔な改行位置 (すっと内容が目に飛び込んでくるか)

  • 縦の線をまっすぐにすると文章に目を通しやすくなる

  • 一貫性と意味のある並び

  • 改行で論理的なグループに分ける、段落に分ける

  • 一貫性のあるスタイルを貫く

  • マクロを使うとキレイになることがある

  • コードを見て本質がすぐに分かるのが理想

     

 

Check 鍵となる考え ポイント
コメントは書き手の意図を伝えること コメントすべきでないもの コードを書いている時に自分の考えを記録する 読み手の立場で必要な情報を書く
  • コードから分かることをコメントにしない

  • ひどい名前はコメントをつけず名前を改善

  • 関数名は自己文書化されいろんなところで使われるのでコメントより名前のほうが重要!

  • コメンタリーを入れる (コードが汚い理由を書いたっていい)

  • キーワードでコードの状態を知らせる(以下は一例)

記法 意味
TODO: あとで手を付ける
FIXME: 既知の不具合があるコード
HACK: あまりキレイじゃない解決策
XXX: 危険!大きな問題がある!
NOTE: 注意
  • 定数にコメントをつける (値の根拠などについて書いておこう)

  • 質問されそうなことを先回りしてコメントする

    • 他の人がコードをみてビックリしそうなことを想像する

    • 他の人がどんなふうに間違えて使う可能性があるか想像する

  • 全体像のコメント

  • 要約コメント

  • ライターズ・ブロックを乗り越える(コメントは悪しき習慣の思想)

 

 

Check 鍵となる考え
コメントは明確で正確に詳細に
  • コメントは画面を多くとるし、読むのが億劫になる。そうなると書く意味がなくなる。

  • あいまいな代名詞は避けるべし

  • 歯切れの悪い文章を磨く

  • プログラムの動作を高次元から説明する

  • 名前付き引数コメントを利用 (Connect(/*timeout_ms = */10)とか) ※インラインコメント

  • 情報密度の高い単語を使って文章を簡潔にする

 

 

ループとロジックの単純化

 

Check 鍵となる考え
制御フローは自然にする
3項演算子は記述が簡潔になるときだけに
do - whileを避ける
関数から早く返す(ガード節)、ネストを浅く
巨大な式は、説明変数や要約変数をうまく使って飲み込み安い大きさに分割し コードの主要な概念を認識
  • 条件式の引数の並びに気を配る

    while(byte_expected > bytes_received)
    よりも
    while(bytes_received < bytes_expected)
    のほうが読みやすい
    左辺 右辺
    調査対象。変化する。 比較対象。あまり変化しない。

     

  • 条件は否定形よりも肯定形を使う(ド・モルガンの法則を活用する)

    if(!debug)
    よりも
    if(debug)
    のほうが読みやすい

 

  • 頭の良いコードに気をつける(あとでわかりにくいことがよくある)

 

 

Check 鍵となる考え
変数を少なくし、変数を追跡しやすくする
変数の生存期間を短くする
変数が頻繁に変更されると現在の値を把握するのが難しくなる
  • 役に立たない一時変数を削除しよう

  • 中間結果を削除してみる

  • 制御フロー変数を削除する(ループから抜けるためだけのフラグとか)

  • 変数の定義を使う直前にできないか検討する