mcpField
L
luau-best-practices

luau-best-practices

github.com/dig1t開発5592 回インストール4 週間前に更新
リポジトリ

luau-best-practices について

LuauでRobloxゲームを開発する人向けのリファレンススキルです。コード構成、サーバー側の検証、エラー処理、メモリのクリーンアップ、一般的なパターンを解説します。

主な機能

  1. 01Luauの命名規則とファイル構成
  2. 02サーバーとクライアントのモジュールパターン
  3. 03外部呼び出しのエラー処理
  4. 04接続の解除とメモリ管理
  5. 05入力検証と不正対策
  6. 06現代的な構文とアンチパターンの指針

活用シーン

  1. 01Robloxゲームのモジュールやサービスの構成
  2. 02サーバーとクライアントの境界や入力検証の確認
  3. 03API障害への対応とリソースのクリーンアップ

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/dig1t/skills --skill luau-best-practices

インストール後、Claude Code で/luau-best-practicesを入力して読み込まれたか確認します。

同梱ファイル

SKILL.md と一緒にインストールされる参考資料やスクリプト。

references/
code-style.md
error-handling.md
memory.md
patterns.md
security.md

詳細

Luau のベストプラクティス

Roblox のゲーム開発における、本番環境向けの品質の高いパターンです。

基本原則

  1. サーバー権限 - ゲームの状態はサーバーが管理し、クライアントは表示を担当します
  2. 早期に失敗させる - 早い段階で検証し、開発中は明確にエラーを通知します
  3. 暗黙より明示 - 巧妙なコードより、意図が明確なコードを優先します
  4. 公開範囲を最小限にする - 必要なものだけを公開します

コードスタイル

命名規則
-- PascalCase: Types, Classes, Services, Modules
type PlayerData = { ... }
local ShopService = {}
local PlayerController = require(...)

-- camelCase: Variables, functions, methods
local playerCount = 0
local function getPlayerData() end
function ShopService:purchaseItem() end

-- SCREAMING_SNAKE_CASE: Constants
local MAX_PLAYERS = 50
local DEFAULT_HEALTH = 100

-- Private with underscore prefix
local function _validateInput() end
local _cache = {}
ファイル構成

ファイル内の順序:--!strict → サービス/インポート → 定数 → 型 → モジュールテーブル → プライベート状態 → プライベート関数 → 公開 API → return。references/code-style.md に完全なテンプレートがあります。

モジュールパターン

サービスパターン(サーバー)
--!strict
local MyService = {}

local _started = false

function MyService:Start()
    assert(not _started, "MyService already started")
    _started = true
    -- Initialize connections, load data
end

function MyService:Stop()
    -- Cleanup for hot-reloading
end

return MyService
コントローラーパターン(クライアント)
--!strict
local MyController = {}

local _player = game:GetService("Players").LocalPlayer

function MyController:Init()
    -- Setup without yielding
end

function MyController:Start()
    -- Connect events, start loops
end

return MyController

その他のパターン(シグナル、状態管理、遅延初期化)については、references/patterns.md を参照してください。

エラー処理

外部呼び出しには pcall を使用する
-- DataStore, HTTP, any Roblox API that can fail
local success, result = pcall(function()
    return dataStore:GetAsync(key)
end)

if not success then
    warn("DataStore failed:", result)
    return nil
end

return result

プログラミングエラー(決して発生すべきでない事象)には assert を使用し、正当に失敗する可能性のある外部呼び出しには pcall と warn を使用します。Result 型と再試行パターンについては、references/error-handling.md を参照してください。

メモリ管理

必ず切断する
local connection: RBXScriptConnection

connection = event:Connect(function()
    -- handler
end)

-- Later, cleanup:
connection:Disconnect()
Maids/Janitors を使用する
local Maid = require(Packages.Maid)

local maid = Maid.new()

maid:GiveTask(event:Connect(handler))
maid:GiveTask(instance)
maid:GiveTask(function()
    -- Custom cleanup
end)

-- Cleanup everything at once
maid:Destroy()

キャッシュ用の弱参照テーブルや、その他のリーク防止パターンについては、references/memory.md を参照してください。

セキュリティのベストプラクティス

サーバー権限
-- BAD: Client tells server what happened
RemoteEvent.OnServerEvent:Connect(function(player, damage)
    target.Health -= damage  -- Client controls damage!
end)

-- GOOD: Server calculates everything
RemoteEvent.OnServerEvent:Connect(function(player, targetId)
    local target = getValidTarget(player, targetId)
    if not target then return end

    local damage = calculateDamage(player)  -- Server calculates
    target.Health -= damage
end)
すべての入力を検証する
RemoteFunction.OnServerInvoke = function(player, itemId, quantity)
    -- Type validation
    if typeof(itemId) ~= "string" then return end
    if typeof(quantity) ~= "number" then return end

    -- Range validation
    if quantity < 1 or quantity > 99 then return end
    if quantity ~= math.floor(quantity) then return end

    -- Business logic validation
    if not Items[itemId] then return end
    if not canAfford(player, itemId, quantity) then return end

    -- Now safe to process
    return purchaseItem(player, itemId, quantity)
end

レート制限やエクスプロイト対策のパターンについては、references/security.md を参照してください。

よくあるアンチパターン

避ける
-- Using wait() - use task.wait()
wait(1)  -- BAD
task.wait(1)  -- GOOD

-- spawn() - use task.spawn()
spawn(fn)  -- BAD
task.spawn(fn)  -- GOOD

-- delay() - use task.delay()
delay(1, fn)  -- BAD
task.delay(1, fn)  -- GOOD

-- Polling when events exist
while true do
    if something then break end
    task.wait()
end
-- GOOD: Use events/signals instead

-- String concatenation in loops
local s = ""
for i = 1, 1000 do
    s = s .. tostring(i)  -- O(n²)
end
-- GOOD: Use table.concat

-- Dot-index chains on instances
workspace.Folder.SubFolder.Part  -- Errors if missing
-- GOOD: Safe navigation
local folder = workspace:FindFirstChild("Folder")
local subFolder = folder and folder:FindFirstChild("SubFolder")
local part = subFolder and subFolder:FindFirstChild("Part")
推奨
-- Generalized iteration
for _, v in ipairs(array) do end  -- OLD
for _, v in array do end  -- MODERN (Luau)

-- If expressions
local x = if condition then a else b  -- Clean ternary

-- Continue in loops
for _, item in items do
    if not item.valid then continue end
    process(item)
end

-- Optional chaining with and
local name = player and player.Character and player.Character.Name

プロジェクト構成

src/
├── Server/
│   ├── init.server.luau      # Bootstrap
│   ├── Services/             # Game services
│   │   ├── DataService.luau
│   │   └── CombatService.luau
│   └── Components/           # Server components
├── Client/
│   ├── init.client.luau      # Bootstrap
│   ├── Controllers/          # Client controllers
│   └── UI/                   # UI components
├── Shared/
│   ├── Types.luau            # Shared type definitions
│   ├── Constants.luau        # Shared constants
│   └── Util/                 # Shared utilities
└── Packages/                 # Wally packages

クイックリファレンス

推奨非推奨
task.wait()wait()
task.spawn()spawn()
task.delay()delay()
for _, v in tfor _, v in pairs(t)
サーバーで検証するクライアントのデータを信頼する
型を使用するあらゆる箇所で any を使用する
イベントを切断する接続を放置する
定数を使用するマジックナンバー/文字列
早期に return する深くネストする
小さな関数200 行以上の関数

参考資料

コメント