---
title: "OpenResty コーディングスタイルガイド - API7.ai"
description: "OpenResty 风格指南包含了关于“如何编写” OpenResty、Lua、NGINX 代码的一般规则。"
url: "https://api7.ai/ja/learning-center/openresty/openresty-coding-style-guide"
---

# OpenResty コーディングスタイルガイド

API7.ai

December 15, 2022

[OpenResty (NGINX + Lua)](https://api7.ai/learning-center/openresty)

多くの開発言語には、開発者にその分野での慣習を伝え、コードのスタイルを一貫させ、一般的な落とし穴を避けるためのコーディング規約があります。PythonのPEP 8はその良い例で、ほぼすべてのPython開発者がこのPythonの作者によって書かれたコーディング規約を読んでいます。

OpenRestyにはまだ独自のコーディング規約がなく、一部の開発者はPRを提出した後、コードスタイルを変更するよう繰り返しレビューされ、多くの時間と労力を消費していますが、これは避けられるものです。

OpenRestyには、コードスタイルを自動的に検出するための2つのLintツールがあります: `luacheck` と `lj-releng` です。前者はLuaおよびOpenRestyの世界で一般的なLintツールであり、後者はOpenResty自身が`Perl`で書いたLintツールです。

私自身は、VS Codeエディタに`luacheck`プラグインをインストールして、コードを書く際に自動提案を行うツールを利用しています。また、プロジェクトのCIでは両方のツールを実行しています。例えば、

```
luacheck -q lua

./utils/lj-releng lua/*.lua lua/apisix/*.lua
```

結局のところ、テスト用のツールがもう一つあっても悪いことはありません。

しかし、これらの2つのツールは、グローバル変数の検出、1行あたりの長さ、その他の最も基本的なコードスタイルの検出に重点を置いており、PythonのPEP 8のような詳細なレベルにはまだ遠く、参照するためのドキュメントもありません。

そこで今日、OpenResty関連のオープンソースプロジェクトでの経験に基づいて、OpenRestyのコーディングスタイルドキュメントをまとめました。この規約は、APISIXやKongなどのAPIゲートウェイのコードスタイルとも一致しています。

## インデント

OpenRestyでは、4つのスペースをインデントマーカーとして使用します。Luaにはそのような構文は必要ありませんが、以下に間違ったコードと正しいコードの2つの例を示します。

```
--No
if a then
ngx.say("hello")
end
```

```
--yes
if a then
    ngx.say("hello")
end
```

便利のために、使用しているエディタでタブを4つのスペースに変更することで操作を簡略化できます。

## スペース

演算子の両側には、スペースを入れて区切る必要があります。以下に間違ったコードと正しいコードの2つの例を示します。

```
--No
local i=1
local s    =    "apisix"
```

```
--Yes
local i = 1
local s = "apisix"
```

## 空白行

多くの開発者は、他の言語からの開発慣習をOpenRestyに持ち込みます。例えば、行末にセミコロンを追加するなどです。

```
--No
if a then
    ngx.say("hello");
end;
```

しかし、実際にはセミコロンを追加するとLuaのコードが非常に見苦しくなり、これは不要です。また、複数行のコードを1行にまとめて簡潔にしようとするべきではありません。これを行うと、エラーを特定する際にどのセクションのコードが問題なのかわからなくなります。

```
--No
if a then ngx.say("hello") end
```

```
--yes
if a then
    ngx.say("hello")
end
```

さらに、関数は2つの空白行で区切る必要があります。

```
--No
local function foo()
end
local function bar()
end
```

```
--Yes
local function foo()
end

local function bar()
end
```

複数の`if elseif`ブランチがある場合も、空白行で区切る必要があります。

```
--No
if a == 1 then
    foo()
elseif a== 2 then
    bar()
elseif a == 3 then
    run()
else
    error()
end
```

```
--Yes
if a == 1 then
    foo()

elseif a== 2 then
    bar()

elseif a == 3 then
    run()

else
    error()
end
```

## 1行あたりの最大長

各行は80文字を超えてはいけません。それを超える場合は、改行して揃える必要があります。また、改行を揃える際には、上下の行の対応関係を反映させる必要があります。以下の例では、2行目の関数の引数は、1行目の左括弧の右側に配置する必要があります。

```
--No
return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst, conf.default_conn_delay)
```

```
--Yes
return limit_conn_new("plugin-limit-conn", conf.conn, conf.burst,
                    conf.default_conn_delay)
```

文字列の連結を揃える場合は、`..`を次の行に配置する必要があります。

```
--No
return limit_conn_new("plugin-limit-conn" ..  "plugin-limit-conn" ..
                    "plugin-limit-conn")
```

```
--Yes
return limit_conn_new("plugin-limit-conn" .. "plugin-limit-conn"
                    .. "plugin-limit-conn")
```

## 変数

この点は以前の記事でも何度か強調されましたが、常にグローバル変数ではなくローカル変数を使用するべきです。

```
--No
i = 1
s = "apisix"
```

```
--Yes
local i = 1
local s = "apisix"
```

変数の命名に関しては、`snake_case`スタイルを使用するべきです。

```
--No
local IndexArr = 1
local str_Name = "apisix"
```

```
--Yes
local index_arr = 1
local str_name = "apisix"
```

一方、定数の場合は、`all-caps`スタイルを使用するべきです。

```
--No
local max_int = 65535
local server_name = "apisix"

--Yes
local MAX_INT = 65535
local SERVER_NAME = "apisix"
```

## テーブル

OpenRestyでは、`table.new`を使用してテーブルを事前に割り当てます。

```
--No
local t = {}
for i = 1, 100 do
   t[i] = i
 end
```

```
--Yes
local new_tab = require "table.new"
 local t = new_tab(100, 0)
 for i = 1, 100 do
   t[i] = i
 end
```

また、配列で`nil`を使用してはいけません。nullを使用する必要がある場合は、`ngx.null`を使用して示します。

```
--No
local t = {1, 2, nil, 3}

--Yes
local t = {1, 2, ngx.null, 3}
```

## 文字列

ホットコードパスで文字列を連結してはいけません。

```
--No
local s = ""
for i = 1, 100000 do
    s = s .. "a"
end
```

```
--Yes
local t = {}
for i = 1, 100000 do
    t[i] = "a"
end
local s =  table.concat(t, "")
```

## 関数

関数の命名も`snake_case`に従います。

```
--No
local function testNginx()
end
```

```
--Yes
local function test_nginx()
end
```

また、関数はできるだけ早く返すべきです。

```
--No
local function check(age, name)
    local ret = true
    if age < 20 then
        ret = false
    end

    if name == "a" then
        ret = false
    end
    -- do something else
    return ret
```

```
--Yes
local function check(age, name)
    if age < 20 then
        return false
    end

    if name == "a" then
        return false
    end
    -- do something else
    return true
```

## モジュール

すべての`require`されたライブラリは`local`化する必要があります。

```
--No
local function foo()
    local ok, err = ngx.timer.at(delay, handler)
end
```

```
--Yes
local timer_at = ngx.timer.at

local function foo()
    local ok, err = timer_at(delay, handler)
end
```

スタイルの一貫性のために、`require`と`ngx`も`local`化する必要があります。

```
--No
local core = require("apisix.core")
local timer_at = ngx.timer.at

local function foo()
    local ok, err = timer_at(delay, handler)
end
```

```
--Yes
local ngx = ngx
local require = require
local core = require("apisix.core")
local timer_at = ngx.timer.at

local function foo()
    local ok, err = timer_at(delay, handler)
end
```

## エラーハンドリング

エラー情報を返す関数の場合、エラー情報を判断して処理する必要があります。

```
--No
local sock = ngx.socket.tcp()
local ok = sock:connect("www.google.com", 80)
ngx.say("successfully connected to google!")
```

```
--Yes
local sock = ngx.socket.tcp()
local ok, err = sock:connect("www.google.com", 80)
if not ok then
    ngx.say("failed to connect to google: ", err)
    return
end
ngx.say("successfully connected to google!")
```

また、自分で書いた関数の場合、エラー情報は文字列形式で2番目のパラメータとして返すべきです。

```
--No
local function foo()
    local ok, err = func()
    if not ok then
        return false
    end
    return true
end
```

```
--No
local function foo()
    local ok, err = func()
    if not ok then
        return false, {msg = err}
    end
    return true
end
```

```
--Yes
local function foo()
    local ok, err = func()
    if not ok then
        return false, "failed to call func(): " .. err
    end
    return true
end
```

## まとめ

これはコーディングスタイルガイドの初期バージョンであり、GitHubで公開して継続的に更新とメンテナンスを行います。この規約を共有して、より多くのOpenRestyユーザーが参加できるようにしてください。

Share article link

Share

Related Posts

[![OpenResty FAQ | OpenRestyの実践的な使い方](https://static.api7.ai/uploads/2023/02/12/jbv9M0zi_Hello%20World%20in%20OpenResty%20%283%29.png)](https://api7.ai/learning-center/openresty/faq-5)

## [OpenResty FAQ | OpenRestyの実践的な使い方](https://api7.ai/learning-center/openresty/faq-5)

[![第3部：OpenRestyを使用してマイクロサービスAPIゲートウェイを構築する方法](https://static.api7.ai/uploads/2023/02/07/3XJXY9Jy_45.png)](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

## [第3部：OpenRestyを使用してマイクロサービスAPIゲートウェイを構築する方法](https://api7.ai/learning-center/openresty/how-to-build-a-microservices-api-gateway-part-3)

Table of Contents

- [インデント](#%E3%82%A4%E3%83%B3%E3%83%87%E3%83%B3%E3%83%88)
- [スペース](#%E3%82%B9%E3%83%9A%E3%83%BC%E3%82%B9)
- [空白行](#%E7%A9%BA%E7%99%BD%E8%A1%8C)
- [1行あたりの最大長](#1%E8%A1%8C%E3%81%82%E3%81%9F%E3%82%8A%E3%81%AE%E6%9C%80%E5%A4%A7%E9%95%B7)
- [変数](#%E5%A4%89%E6%95%B0)
- [テーブル](#%E3%83%86%E3%83%BC%E3%83%96%E3%83%AB)
- [文字列](#%E6%96%87%E5%AD%97%E5%88%97)
- [関数](#%E9%96%A2%E6%95%B0)
- [モジュール](#%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)
- [エラーハンドリング](#%E3%82%A8%E3%83%A9%E3%83%BC%E3%83%8F%E3%83%B3%E3%83%89%E3%83%AA%E3%83%B3%E3%82%B0)
- [まとめ](#%E3%81%BE%E3%81%A8%E3%82%81)
