〜VBAを使ったら絶対に後悔する7つの理由〜 社内でLTしたスライドです
VBAナメてた@narazaka
View Slide
奈良阪自己紹介Twitter:Github:npm:CPAN:RubyGems:ドリコム2015新卒入社 サーバーサイドRuby好きな言語: Perl / CoffeeScript / Ruby / C# / Ceylon?その他:伺か/漫画読み描き/OPアニメ愛好家/鉄@narazaka@Narazaka@narazakaNARAZAKANarazaka
VBA(Visual Basic for Applications)1994年のExcel5.0から付属したマクロ用言語Excelが有名だがWordやPowerPoint等でも使える
顧客が説明した要件プランナーさん:クエスト作成を便利にしてや奈良阪: xlsx使っとるしVBAやと移行コスト低そうか?
プログラマの見積もりプランナーさん:ウィッスオナシャス奈良阪:メンテコスト高いらしい奈良阪:綺麗にかいたらそんなでもないやろ(慢心)
VBAナメてました
「Excelマクロつらい」
謎のセル指定
なるほど……?
VBA、オブジェクト指向言語らしい?クラス書いたらよくね?
適切な変数名でマシになるっしょ?table_area = Range(area_begin, area_end)
……
クラスにもした変数名関数名とかにも気を配った
でもそういう問題ではなかった
VBA||20世紀のMS製品
最近のMicrosoftに毒気を抜かれて忘れていた
生産性が惨殺される体感
古き良きM$を思い出させてくれる糞仕様の数々
7連発
VBAを使ったら絶対に後悔する7つの理由(煽りタイトル)
1.不完全な型システム
VBAは一応オプショナルな変数型指定を持ちます
TypeScriptのように、変数宣言時や関数宣言時にオプションで型をつけられるこれは良い
型付で宣言された変数はエディタ上でインスペクタが出て使えるメソッドとかが出てくるこれも良い
型情報最高!!
にもかかわらず
エディタでもコンパイラでも型チェックされない
?
「型が一致しません (エラー 13)」はランタイムエラー
引数の順番とか間違えてても全部ランタイムエラー
せっかく入力したのに……型情報の持ち腐れ
不完全な型システムややつらい
disばかりでは一面的なので他言語などと比較して※許せる点エディタ上だけとはいえインスペクタ働くのは良い実行時型判定でエラるので早期エラー発見にはなるどちらかといえば「口惜しい」その他付随したしんどい点変数名の補完はしてくれないのでめんどい
2.プリミティブ型とオブジェクト型で代入の方法が異なる
VBAは一応オブジェクト指向言語
プリミティブ型とオブジェクト型C++やJavaと同じ感じプリミティブ型: Integer, Boolean等オブジェクト型: Range,ユーザ定義等
プリミティブ型とオブジェクト型で代入の方法が異なる
プリミティブ型はValue = 1
オブジェクト型はSet Value = New MyClass
オブジェクト型の場合先頭にをつけなければならない
ミス→ランタイムエラーエディタは検出してくれないしかもエラーメッセージが謎
検出困難なれるとそこまで間違わなくなるが、書き始めた初期はヤバかった。
似たようなつらみ関数とサブルーチン返値あり ->関数 (Function)返値なし ->サブルーチン (Sub)の別もある(Fortranにもある)
呼び出し書式が違う
関数は引数に括弧をつけるSet Data = Table.GetData(Row, True)
サブルーチンではつけないTable.AddData RowData, True
関数呼び出しの不整合→ランタイムエラーエディタはスルー
つらい
プリミティブ型とオブジェクト型で代入の方法が異なる関数とサブルーチンの呼び出し方法が異なるつらい
※許せる点C++でも値とポインタとの別があるし、(*をつける場合が有るので)代入方法が異なると言えなくもない関数とサブルーチンの別はFortranにもある(サブルーチンはcallを先頭につけて呼び出す)
3.関数が第一級オブジェクトではない
自分がこれまで使った言語JavaScript(ES3,5,2015)Perl5.8~5.22Fortran95CC++(03、11)DJavaPython3Ruby(2.0以降)C#(5.0、6.0)Excel VBATypeScriptCoffeeScript華和梨8.2.8(kis)Windowsバッチファイルbashスクリプト
VBA、バッチファイル、シェルスクリプトのみ関数が第一級オブジェクトとして扱えない
eachmaplterVBAでは本質的に 以外で実装が出来ない
For Next回すしかない
関数が第一級オブジェクトではないのあるのに慣れてるので結構辛い
※許せる……?点evalすれば使えるDSLではそういうこともある
4.エディタで1行ごとに構文チェックが走る
(厳密には言語の特徴ではないが)エディタで1行ごとに構文チェックが走るのがひどい
Visual StudioとかのIDEも改行したら行整形したりするが……
関数を書こう
if文を書こう
FirstRowIndexという定数と比較したい変数名補完が効かないし長いからコピーしてこよう
カーソルを別の行へ
!?
行ごとに文完結してないとエラーがダイアログで出るいちいちOK押さないと別の編集ができないついでにまともな修正候補は出ない
とりあえず意味のない値で文完結させて別の行へ
きっとこれを面倒がって短いAとかBとかの変数名が書かれるんだろうと思うと……
エディタで1行ごとに構文チェックが走ってしかもいちいちダイアログが出るつらい
※許せる?点不十分すぎるが文法エラー出してくれるのは良い
5.ソースがxlsxバイナリの中に保存される
つまり自然にバージョン管理や差分比較することが出来ない
※許せる点xlsxがメインでその付属スクリプトという性格からしょうがない面がある比較的許せる
ソースがxlsxバイナリの中に保存されるのつらいけど許せる
6.継承ができない
「VBAは一応オブジェクト指向言語」
クラスの継承が出来ない
運用で回避あるあるクラスにアクセス制御がなかったりするLL命名規則とかでなんとかする
回避できないVBAはアクセス制御があるのに継承がない委譲しよう→関数が第一級ではないのでつらそう
インターフェースは継承をすることは可能' Class1Implements Class2Dim Obj1 As Class1Set Obj1 = new Class1Call Obj1.class2method ' Dim Obj1 As Class1Set Obj1 = new Class1Dim Obj2 As Class2Set Obj2 = Obj1 ' !?Call Obj2.class2method
他OOP系のつらみコンストラクタに引数が渡せない
Set Obj = New MyClass(hoge) '
Set Obj = New MyClassObj.Setup(hoge)
継承ができないコンストラクタに引数が渡せないごっつつらい
※許せる点一応クラスは作れる
7.スタックトレースが存在しない呼び出し元しかわからない
エラーにスタックトレースがつかないエラーが起こった処理の呼び出し元しかわからない
最高にヤバい
大抵の言語ではエラー時「スタックトレース」が出る
スタックトレースのない言語はシェルスクリプト等他にも存在するしかしそれらは最低限実際にエラーになったソース行がわかる。
in VBA
エラー発生!
情報1:エラー内容とエラーコード(この時点では行がわからない)
情報2:呼び出し元の行情報
以上
エラー時に分かる情報情報1:エラー内容とエラーコード(型が一致しません (エラー 13))くらいの超簡易な情報情報2:呼び出し元の行情報
エラー内容詳細を見たいヘルプを押しても
検索しても
ググるしかない
エラーのたびに……1.エラー内容とエラーコード2.呼び出し元の行情報しか提供されないのでエラー内容詳細ググるエラーの起きた場所呼び出し元からブレークポイントをふりつつ関数を1つずつ自分でたどって行を絞り込んでいく
苦行
スタックトレースが存在しない呼び出し元しかわからない
※許せない
7つの大罪1.不完全な型システム2.プリミティブ型とオブジェクト型で代入の方法が異なる3.関数が第一級オブジェクトではない4.エディタで1行ごとに構文チェックが走る5.ソースがxlsxバイナリの中に保存される6.継承ができない7.スタックトレース不在 呼び出し元しかわからない
7つの知見1.合理的な型システム2.代入や呼び出しの方法が一貫している3.第一級関数4.柔軟なIDE5.テキストでソースが保存できる6.継承ができる7.スタックトレースがある素晴らしい
当たり前に感謝
教訓
次はVBA以外でやる