18
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Elm 2Advent Calendar 2017

Day 3

Elm Analyse でコード品質を担保する

Last updated at Posted at 2017-12-02

Elm2 アドベントカレンダー 2017 の3日目です。

Elm Analyse は Elm コードの良くない匂いを嗅ぎつけて指摘してくれるツールです。

使い方

npm (または yarn)でインストールします。

npm install -g elm-analyse

プロジェクトのルートディレクトリでコマンドを打つと警告が一覧で出力されます。

elm-analyse

(場合によっては多少待ちます)

チェック事項

以下の項目をチェックします。

CoreArrayUsage
Elm 0.18 の Array にはバグがあるので、今は Skinney/elm-array-exploration を使った方がいい(0.19 でコアにマージされます)。

DebugCrash
Debug.crash が使われている。

DebugLog
Debug.log が使われている。

DropConcatOfLists
リストを無駄な結合 [1,2,3] ++ [4,5][1,2,3,4,5] のようにまとめた方が良い。

DropConsOfItemAndList
リストを無駄な結合 1::[2,3,4][1,2,3,4] のようにまとめた方が良い。

DuplicateImport
同じモジュールを2回インポートしている。

-- BAD
import Html exposing (text)
import Html exposing (Html)

DuplicateImportedVariable
同じ値を2度インポートしている。

-- BAD
import Html exposing (Html, text, Html)

DuplicateRecordFieldUpdate
レコードの同じフィールドを重複して更新している。

-- BAD
{ person | name = "John", name = "Jane" }

ExposeAll
できる限りモジュールが公開するインターフェイスを絞った方が良い。

-- BAD
module Foo exposing (..)

NoUncurriedPrefix
(++) "Hello " "World" のように中置演算子を無駄に関数として使わず、素直に "Hello " ++ "World" とした方が良い。

FunctionInLet
let ~ in 中に関数を宣言する必要はあまりないので、トップレベルに置けるなら置いた方が良い。

-- BAD
foo : Int -> Int
foo x =
    let
        somethingIShouldDefineOnTopLevel : Int -> Int
        somethingIShouldDefineOnTopLevel y =
            y + 1
    in
        somethingIShouldDefineOnTopLevel x

ImportAll
ワイルドカードで import すると他の人が読んだときにどのモジュールの関数かわかりにくくなるので、避けた方がいい。

-- BAD
import Html exposing (..)

LineLengthExceeded
一行の文字数が長すぎる(デフォルトの閾値は 150 文字)

MultiLineRecordFormatting
レコードは複数行で宣言した方が読みやすい。

-- BAD
type alias Person =
    { name : String , age : string , address : Address }

-- GOOD
type alias Person =
    { name : String
    , age : string
    , address : Address
    }

NoTopLevelSignature
トップレベルの関数や値には型をつけた方がいい。

-- BAD
foo =
    1

NonStaticRegex
動的に正規表現を作ると実行時エラーを起こす可能性があるため、トップレベルに宣言した方がいい。

-- BAD
foo x =
    let
        myInvalidRegex = Regex.regex "["
    in
        (myInvalidRegex, x)

RedefineVariable
同じ変数名で外の変数を上書きしない方が混乱が少ない。

-- BAD
foo : Maybe Int -> Int
foo x =
    case x of
        Just x ->
            x
        Nothing ->
            1

SingleFieldRecord
1つのフィールドしかないレコードは obsolete (廃れた習慣?)だ。(意図が良くわからないが Haskell でそういう書き方をするから?)

-- BAD
type Model =
    Model { input : String }

TriggerWords
TODOFIXME のようなコメントを残したままにしない方が良い(単語は設定で変えられる)。

UnformattedFile
elm-format されていない。

UnnecessaryListConcat
不必要に List.concat している。単に ++ で繋げた方が良い。

-- BAD
foo : List Int
foo =
    List.concat [ [ 1, 2 ,3 ], [ a, b, c] ]

UnnecessaryParens
不必要な括弧は取り除いた方が良い。(それでも括弧が好きな人は Lisp をやろうと書いてある)

-- BAD
someCall =
    (foo 1) 2

UnnecessaryPortModule
port module と不必要に宣言されている。

-- BAD
port module Foo exposing (notAPort)

notAPort : Int
notAPort = 1

UnusedImport
インポートされているが使われていないモジュールがある。

-- BAD
import Unused

UnusedImportAlias
import ... as ... でエイリアスをつけたモジュール名が使われていない。

module Foo exposing (main)

-- BAD( H が使われていない)
import Html as H exposing (Html, text)

main : Html a
main =
    text "Hello"

UnusedImportedVariable

module Foo exposing (thing)

-- BAD ( div が使われていない)
import Html exposing (Html, div, text)

main : Html a
main =
    text "Hello World!"

UnusedPatternVariable
パターンマッチで束縛した変数が使われていない。

-- BAD ( age が使われていない)
sayHello {name, age} = "Hello " ++ name

UnusedTopLevel
トップレベルの関数が使われていない。

UnusedTypeAlias
type alias を宣言しているが使われていない。

UnusedVariable
変数が使われていない。

-- BAD
foo : String -> Int
foo x =
    1

UseConsOverConcat
[ a ] ++ foo ではなく a :: foo と書いた方がいい。

チェック項目の設定

**異議あり!**という項目が多々あったと思うので、プロジェクトのルートディレクトリに elm-anayse.json を置いてください。true のものだけがチェックされます。

{
  "checks": {
    "DebugCrash": false,
    "DebugLog": false,
    "DropConcatOfLists": false,
    "DropConsOfItemAndList": false,
    "DuplicateImport": true,
    "DuplicateImportedVariable": true,
    "ExposeAll": false,
    "ImportAll": false,
    "LineLengthExceeded": false,
    "MultiLineRecordFormatting": false,
    "NoTopLevelSignature": false,
    "NoUncurriedPrefix": true,
    "NonStaticRegex": true,
    "RedefineVariable": false,
    "SingleFieldRecord": false,
    "UnnecessaryListConcat": false,
    "UnnecessaryParens": true,
    "UnusedImport": true,
    "UnusedImportAlias": true,
    "UnusedImportedVariable": true,
    "UnusedPatternVariable": false,
    "UnusedTopLevel": true,
    "UnusedTypeAlias": true,
    "UnusedVariable": false,
    "UseConsOverConcat": false,
    "UnformattedFile": true
  },
  "TriggerWords": {
    "words": ["todo", "fixme"]
  }
}

レポートをブラウザで表示

--serve オプションで結果をブラウザで表示します。

elm-analyse --serve

localhost:3000 にアクセスすると、警告の一覧やモジュールの依存関係が表示されます。

Screen Shot 2017-12-03 at 1.10.26.png

問題のコードの位置を教えてくれるのが嬉しかったりします。

Screen Shot 2017-12-03 at 1.07.46.png

まとめ

チーム開発のときにプロジェクトでルールを決めて使うと、自動でチェックできて便利かもしれませんよ!

18
2
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
18
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?