Skip to main content

Code Style Guide

This guide covers coding standards for contributing to DNS-MNS.

General Principles

  1. Keep it simple - DNS-MNS should be easy to understand and modify
  2. Be consistent - Follow existing patterns in the codebase
  3. Comment wisely - Explain the why, not the what
  4. Test thoroughly - Verify changes work on multiple platforms

Bash Script Standards

Indentation

Use 4 spaces for indentation (not tabs):
# Good
if [ "$condition" = true ]; then
    echo "Indented with 4 spaces"
    if [ "$nested" = true ]; then
        echo "Nested with 4 more spaces"
    fi
fi

# Bad - using tabs
if [ "$condition" = true ]; then
	echo "Indented with tab"
fi

Variable Naming

Use descriptive, lowercase names with underscores:
# Good
dns_server_ip="1.1.1.1"
primary_dns=""
ping_result=""
test_count=0

# Bad
dnsServerIp="1.1.1.1"  # camelCase
DNS="1.1.1.1"          # too short
x=0                    # meaningless

Quoting

Always quote variables to prevent word splitting:
# Good
echo "$dns_server"
if [ -n "$result" ]; then
    process "$filename"
fi

# Bad
echo $dns_server
if [ -n $result ]; then
    process $filename
fi

Function Definitions

Use descriptive function names with lowercase and underscores:
# Good
test_dns_ping() {
    local server_ip="$1"
    local timeout="${2:-2}"
    
    ping -c 3 -W "$timeout" "$server_ip"
}

# Bad
TestDnsPing() {      # PascalCase
    ping -c 3 $1     # unquoted, no local
}

Local Variables

Use local for function variables:
# Good
calculate_score() {
    local ping_time="$1"
    local dns_time="$2"
    local score
    
    score=$(echo "$ping_time * 0.7 + $dns_time * 0.3" | bc)
    echo "$score"
}

# Bad - pollutes global namespace
calculate_score() {
    ping_time="$1"
    dns_time="$2"
    # ...
}

Conditionals

Use [[ ]] for bash conditionals (more features, safer):
# Good
if [[ "$os_type" == "linux" ]]; then
    set_dns_linux
elif [[ "$os_type" == "macos" ]]; then
    set_dns_macos
fi

# Also acceptable for POSIX compatibility
if [ "$os_type" = "linux" ]; then
    set_dns_linux
fi

Error Handling

Check command results and handle errors:
# Good
if ! ping -c 1 "$server" &>/dev/null; then
    echo "Error: Cannot reach $server"
    return 1
fi

# Or with set -e for critical sections
set -e
important_command
set +e

# Bad - ignoring errors
ping -c 1 "$server"
next_command

Comments

When to Comment

Comment on:
  • Complex algorithms
  • Non-obvious logic
  • Platform-specific workarounds
  • Important decisions
# Good - explains why
# Use 70/30 weighting because ping is more relevant for gaming
# than DNS resolution time
score=$(echo "$ping * 0.7 + $dns * 0.3" | bc)

# Good - explains workaround
# macOS ping doesn't support -W, use -t instead
if [[ "$os" == "macos" ]]; then
    ping -c 3 -t 2 "$server"
fi

# Bad - states the obvious
# Ping the server
ping -c 3 "$server"

Function Documentation

Document complex functions:
# Tests DNS server ping response time
# Arguments:
#   $1 - Server IP address
#   $2 - Timeout in seconds (optional, default: 2)
# Returns:
#   Average ping time in milliseconds, or "timeout" on failure
test_dns_ping() {
    local server_ip="$1"
    local timeout="${2:-2}"
    # ...
}

File Organization

Script Structure

Organize scripts in this order:
  1. Shebang and header
  2. Constants and configuration
  3. Utility functions
  4. Core functions
  5. Main menu functions
  6. Main execution
#!/usr/bin/env bash
#
# DNS-MNS - DNS Manager for Network Speed
# Version: 1.1.0
#

# === CONSTANTS ===
VERSION="1.1.0"
CONFIG_DIR="$HOME/.dns-mns"

# === UTILITY FUNCTIONS ===
log_info() { ... }
log_error() { ... }

# === CORE FUNCTIONS ===
test_dns_ping() { ... }
set_dns_linux() { ... }

# === MENU FUNCTIONS ===
show_main_menu() { ... }
handle_selection() { ... }

# === MAIN ===
main() {
    check_requirements
    show_main_menu
}

main "$@"

Platform Compatibility

Portable Commands

Use portable options when possible:
# Good - works on most systems
ping -c 3 "$server"

# Platform-specific - document and handle
if [[ "$OSTYPE" == "darwin"* ]]; then
    ping -c 3 -t 2 "$server"  # macOS
else
    ping -c 3 -W 2 "$server"  # Linux
fi

Check Command Availability

# Good
if command -v dig &>/dev/null; then
    use_dig_for_testing
else
    use_ping_only
fi

# Bad - assumes command exists
dig @"$server" google.com

Testing Checklist

Before submitting changes:

Tools

ShellCheck

Use ShellCheck to catch common issues:
# Install
sudo apt install shellcheck  # Debian/Ubuntu
brew install shellcheck      # macOS

# Run
shellcheck dns-mns.sh

Syntax Check

Verify syntax without executing:
bash -n dns-mns.sh

Example: Good vs Bad

Bad Code

function testDNS {
x=$1
ping -c 3 $x | grep avg | awk -F'/' '{print $5}'
}
result=$(testDNS 1.1.1.1)
if [ $result < 50 ]; then
echo good
fi

Good Code

# Tests DNS server and returns average ping time
# Args: $1 = server IP
# Returns: ping time in ms, or empty on failure
test_dns_ping() {
    local server_ip="$1"
    local result
    
    result=$(ping -c 3 "$server_ip" 2>/dev/null | grep 'avg' | awk -F'/' '{print $5}')
    echo "$result"
}

ping_time=$(test_dns_ping "1.1.1.1")
if [[ -n "$ping_time" ]] && (( $(echo "$ping_time < 50" | bc -l) )); then
    echo "Good ping time: ${ping_time}ms"
fi