Andy Williams
Best practices for excellent Fyne apps
Clean and maintainable code for the life of your project
Project Setup
• Source Control
• Go module unique name
• Gofmt/goimports & go vet
• [Link]/x/tools/cmd/goimports
• Static Check
• [Link]/go/tools/cmd/staticcheck
• Complexity check
• [Link]/fzipp/gocyclo/cmd/gocyclo
Automation of Checks
• Git Hook (pre-commit)
• Configured for each git clone (local)
• Continuous Integration
• Run vet, formatter, static check
• Execute tests
• Check code coverage
Packages
• Don’t add packages too soon
• main package at project root
• Internal packages for related code
• Separate UI from app logic
• One file for each app GUI area
Small files, small functions, clean code
• Multiple files with clear names
• One main type per file
• Keep functions simple, one main purpose
• Split UI setup into many smaller functions
Unit testing
Render testing
• Validate that a component or screen renders as expected
• Compare to .PNG or .XML golden file
• [Link] compares visually
• [Link] compares structure
• testdata folder for comparison files
• testdata/failed will be used when tests fail
Use [Link]
• Store metadata in repo
• Reproducible builds
• Avoiding build scripts
• Smoother release process
Custom Widgets
• Maximum one per file
• Unit tests for all behaviour
• UI test for validating look/layout
• Expose behaviour only
• Store user state in widget
• Don’t store renderer reference
Custom Widgets - Behaviour API
• Create type that extends BaseWidget
• Call ExtendBaseWidget() in constructor
• Export fields that are used in configuration
• Create public methods that expose behaviour
Custom Widgets - Behaviour API
Custom Widgets - Renderer
• Important state in widget
• Disposable information in renderer
• Read all state in Refresh()
• Adapt to size available in Layout()
• Free any resources in Destroy()
Custom Widgets - Renderer
Custom Widgets - SimpleRenderer
• Helper for trivial widgets
• Avoid creation of custom renderer
• Pass object(s) to NewSimpleRenderer
• Send changes to objects in Refresh()
• Object will fill space available
Custom Widgets - SimpleRenderer
And Remember…
• Export only what should be public
• Document all of your APIs
• Naming is important, make sure your API is clear
• Start simple, ask community for help