Standar Coding
Gaya kode, konvensi, dan praktik terbaik untuk Wails v3
Gaya Kode dan Konvensi
Mengikuti standar coding yang konsisten membuat codebase lebih mudah dibaca, dipelihara, dan dikontribusikan.
Standar Kode Go
Format Kode
Gunakan alat format Go standar:
# Format all code
gofmt -w .
# Use goimports for import organization
goimports -w .
Wajib: Semua kode Go harus lulus gofmt dan goimports sebelum commit.
Konvensi Penamaan
Paket:
- Huruf kecil, satu kata jika memungkinkan
package application,package events- Hindari underscore atau mixed caps
Nama Exported:
- PascalCase untuk tipe, fungsi, konstanta
type WebviewWindow struct,func NewApplication()
Nama Unexported:
- camelCase untuk tipe, fungsi, variabel internal
type windowImpl struct,func createWindow()
Interface:
- Dinamai berdasarkan perilaku:
Reader,Writer,Handler - Interface satu method: nama dengan akhiran
-er
// Good
type Closer interface {
Close() error
}
// Avoid
type CloseInterface interface {
Close() error
}Penanganan Error
Selalu periksa error:
// Good
result, err := doSomething()
if err != nil {
return fmt.Errorf("failed to do something: %w", err)
}
// Bad - ignoring errors
result, _ := doSomething()Gunakan error wrapping:
// Wrap errors to provide context
if err := validate(); err != nil {
return fmt.Errorf("validation failed: %w", err)
}Buat tipe error kustom jika diperlukan:
type ValidationError struct {
Field string
Value string
}
func (e *ValidationError) Error() string {
return fmt.Sprintf("invalid value %q for field %q", e.Value, e.Field)
}Komentar dan Dokumentasi
Komentar paket:
// Package application provides the core Wails application runtime.
//
// It handles window management, event dispatching, and service lifecycle.
package applicationDeklarasi exported:
// NewApplication creates a new Wails application with the given options.
//
// The application must be started with Run() or RunWithContext().
func NewApplication(opts Options) *Application {
// ...
}Komentar implementasi:
// processEvent handles incoming events from the runtime.
// It dispatches to registered handlers and manages event lifecycle.
func (a *Application) processEvent(event *Event) {
// Validate event before processing
if event == nil {
return
}
// Find and invoke handlers
// ...
}Struktur Fungsi dan Method
Jaga fungsi tetap fokus:
// Good - single responsibility
func (w *Window) setTitle(title string) {
w.title = title
w.updateNativeTitle()
}
// Bad - doing too much
func (w *Window) updateEverything() {
w.setTitle(w.title)
w.setSize(w.width, w.height)
w.setPosition(w.x, w.y)
// ... 20 more operations
}Gunakan early return:
// Good
func validate(input string) error {
if input == "" {
return errors.New("empty input")
}
if len(input) > 100 {
return errors.New("input too long")
}
return nil
}
// Avoid deep nestingConcurrency
Gunakan context untuk pembatalan:
func (a *Application) RunWithContext(ctx context.Context) error {
select {
case <-ctx.Done():
return ctx.Err()
case <-a.done:
return nil
}
}Lindungi state bersama dengan mutex:
type SafeCounter struct {
mu sync.Mutex
count int
}
func (c *SafeCounter) Increment() {
c.mu.Lock()
defer c.mu.Unlock()
c.count++
}Hindari goroutine leak:
// Good - goroutine has exit condition
func (a *Application) startWorker(ctx context.Context) {
go func() {
for {
select {
case <-ctx.Done():
return // Clean exit
case work := <-a.workChan:
a.process(work)
}
}
}()
}Testing
Penamaan file test:
// Implementation: window.go
// Tests: window_test.goTable-driven test:
func TestValidate(t *testing.T) {
tests := []struct {
name string
input string
wantErr bool
}{
{"empty input", "", true},
{"valid input", "hello", false},
{"too long", strings.Repeat("a", 101), true},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
err := validate(tt.input)
if (err != nil) != tt.wantErr {
t.Errorf("validate() error = %v, wantErr %v", err, tt.wantErr)
}
})
}
}Standar JavaScript/TypeScript
Format Kode
Gunakan Prettier untuk format konsisten:
{
"semi": false,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5"
}Konvensi Penamaan
Variabel dan fungsi:
- camelCase:
const userName = "John"
Class dan tipe:
- PascalCase:
class WindowManager
Konstanta:
- UPPERSNAKECASE:
const MAX_RETRIES = 3
TypeScript
Gunakan tipe eksplisit:
// Good
function greet(name: string): string {
return `Hello, ${name}`
}
// Avoid implicit any
function process(data) { // Bad
return data
}Definisikan interface:
interface WindowOptions {
title: string
width: number
height: number
}
function createWindow(options: WindowOptions): void {
// ...
}Format Pesan Commit
Gunakan Conventional Commits:
<type>(<scope>): <subject>
<body>
<footer>Tipe:
feat: Fitur barufix: Perbaikan bugdocs: Perubahan dokumentasirefactor: Refactoring kodetest: Menambah atau memperbarui teschore: Tugas maintenance
Contoh:
feat(window): add SetAlwaysOnTop method
Implement SetAlwaysOnTop for keeping windows above others.
Adds platform implementations for macOS, Windows, and Linux.
Closes #123fix(events): prevent event handler memory leak
Event listeners were not being properly cleaned up when
windows were closed. This adds explicit cleanup in the
window destructor.Panduan Pull Request
Sebelum Submit
- Kode lulus
gofmtdangoimports - Semua tes lulus (
go test ./...) - Kode baru memiliki tes
- Dokumentasi diperbarui jika diperlukan
- Pesan commit mengikuti konvensi
- Tidak ada konflik merge dengan
master
Template Deskripsi PR
## Description
Brief description of what this PR does.
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
How was this tested?
## Checklist
- [ ] Tests pass
- [ ] Documentation updated
- [ ] No breaking changes (or documented)Proses Code Review
Sebagai Reviewer
- Bersikap konstruktif dan hormat
- Fokus pada kualitas kode, bukan preferensi pribadi
- Jelaskan mengapa perubahan disarankan
- Setujui setelah puas
Sebagai Author
- Tanggapi semua komentar
- Minta klarifikasi jika diperlukan
- Lakukan perubahan yang diminta atau jelaskan mengapa tidak
- Terbuka terhadap feedback
Praktik Terbaik
Performa
- Hindari optimisasi prematur
- Profil sebelum mengoptimalkan
- Gunakan benchmark untuk kode kritis performa
func BenchmarkProcess(b *testing.B) {
for i := 0; i < b.N; i++ {
process(testData)
}
}Keamanan
- Validasi semua input pengguna
- Sanitasi data sebelum ditampilkan
- Gunakan
crypto/randuntuk data acak - Jangan pernah log informasi sensitif
Dokumentasi
- Dokumentasikan API exported
- Sertakan contoh dalam dokumentasi
- Perbarui docs saat mengubah API
- Jaga README tetap mutakhir
Kode Spesifik Platform
Penamaan File
window.go // Common interface
window_darwin.go // macOS implementation
window_windows.go // Windows implementation
window_linux.go // Linux implementationBuild Tags
//go:build darwin
package application
// macOS-specific codeLinting
Jalankan linter sebelum commit:
# golangci-lint (recommended)
golangci-lint run
# Individual linters
go vet ./...
staticcheck ./...
Pertanyaan?
Jika Anda tidak yakin tentang standar apa pun:
- Periksa kode yang ada untuk contoh
- Tanya di Discord
- Buka diskusi di GitHub