# เขียน Dart อย่างมีสไตล์

#Dev#Dart#Flutter

เขียนโค้ดในภาษา Dart/Flutter ยังไงไม่ให้โดนด่าบรรพบุรุษ
ซึ่งผมจะเอาข้อมูลมาจาก Effective Dart (opens new window) โดยเนื้อหาจะเป็นการให้เขียนโค้ดในภาษา Dart ไปในรูปแบบเดียวกันครับ

Cover

# เบื้องต้น

จะมีการแบ่งแต่ละส่วนออกเป็นส่วนย่อยๆ โดยมีคำดังต่อไปนี้

  • ควร เป็นสิ่งควรจะทำตามเสมอ ไม่มีเหตุผลให้ไม่ทำตามนี้
  • อย่า เป็นสิ่งที่ไม่ควรทำตาม
  • แนะนำ ให้ทำตาม แต่จะไม่ทำตามก็ได้ในบางกรณี
  • หลีกเลี่ยง ไม่ควรทำ เว้นเสียแต่ว่ามีเหตุให้ต้องทำ
  • คิดก่อน อาจจะทำตาม หรือไม่ทำตามก็ได้แล้วแต่สถานการณ์

อีกส่วนที่สำคัญในการเขียนโค้ดที่ดีก็คือการมีรูปแบบที่ดี ไม่ว่าจะเป็นการตั้งชื่อ การจัดเรียง จะช่วยให้โค้ดดูเหมือนๆกัน ทำให้คนที่มาอ่านสามารถแก้ และเข้าใจโค้ดของเราได้มากยิ่งขึ้น

# การตั้งชื่อตัวแปรและอื่นๆ

มีสามรูปแบบ

  1. UpperCamelCase ขึ้นต้นแต่ละคำด้วยตัวพิมพ์ใหญ่
  2. lowerCamelCase ขึ้นต้นแต่ละคำด้วยตัวพิมพ์ใหญ่ ยกเว้นคำแรกสุดที่เป็นตัวพิมพ์เล็กทั้งหมด
  3. lowercase_with_underscores พิมพ์ด้วยตัวพิมพ์เล็กทั้งหมด โดยจะคั่นแต่ละคำด้วย _ (Underscore)

# ควร ตั้งชื่อ Type หรือชนิดด้วย UpperCamelCase

ตั้งชื่อ Class, enum, typedef, หรือชนิดต่างๆด้วยตัวพิมพ์ใหญ่ขึ้นต้นแต่ละคำโดยไม่มีอะไรคั่นแต่ละคำ

class SliderMenu { ... }

class HttpRequest { ... }

typedef Predicate<T> = bool Function(T value);

# ควร ตั้งชื่อ Library, Package, Folder, File ด้วย lowercase_with_underscores

ในบางระบบไฟล์การตั้งชื่อไฟล์เป็นตัวพิมพ์เล็กหรือใหญ่ให้ผลที่เหมือนกัน เพื่อหลีกเลี่ยงปัญหา เราจึงควรตั้งชื่อสิ่งเหล่านี้ด้วยตัวพิมพ์เล็กทั้งหมด แล้วคั่นแต่ละคำด้วย _

// ดี
library peg_parser.source_scanner;

import 'file_system.dart';
import 'slider_menu.dart';
// ไม่ดี
library pegparser.SourceScanner;

import 'file-system.dart';
import 'SliderMenu.dart';

# ควร ตั้งชื่อ Library ที่ import มาด้วย lowercase_with_underscores

// ดี
import 'dart:math' as math;
import 'package:angular_components/angular_components'
    as angular_components;
import 'package:js/js.dart' as js;
// ไม่ดี
import 'dart:math' as Math;
import 'package:angular_components/angular_components'
    as angularComponents;
import 'package:js/js.dart' as JS;

# ควร ตั้งชื่อตัวแปรทั่วๆไป หรือชื่อฟังก์ชันด้วย lowerCamelCase

var item;

HttpRequest httpRequest;

void align(bool clearItems) {
  // ...
}

# แนะนำ ให้ใช้ lowerCamelCase สำหรับตัวแปรประเภท Constant ในโค้ดใหม่ๆ

// ดี
const pi = 3.14;
const defaultTimeout = 1000;
final urlScheme = RegExp('^([a-z]+):');

class Dice {
  static final numberGenerator = Random();
}
// ไม่ดี
const PI = 3.14;
const DefaultTimeout = 1000;
final URL_SCHEME = RegExp('^([a-z]+):');

class Dice {
  static final NUMBER_GENERATOR = Random();
}

ซึ่งอาจจะยังใช้การตั้งชื่อในรูปแบบ SCREAMING_CAPS ก็ได้ ถ้า

  1. เพิ่มโค้ดลงใน Library หรืดโค้ดเดิมๆที่ใช้ SCREAMING_CAPS
  2. ถ้ามีการ Generate โค้ดแล้วชื่อต้องสัมพันธ์กับโค้ดภาษาอื่น

Note

เหตุผลที่ไม่ใช้ SCREAMING_CAPS เพราะว่า

  1. SCREAMING_CAPS มันดูไม่สวยงามในบางกรณี
  2. ตัวแปรประเภท Constant ในหลายๆครั้งมักจะถูกเปลี่ยนเป็น final ทำให้ชื่อต้องถูกเปลี่ยนไปด้วย
  3. ตัวแปร values ที่ประกาศใน enum เป็น Constant และเป็นตัวพิมพ์เล็ก

# อย่า ใช้ _ นำหน้าชื่อตัวแปร หรือฟังก์ชันที่ไม่ได้ต้องการให้เป็น private

ในภาษา Dart เราจะใช้ _ ใน class ในการระบุความเป็น private

# อย่า ใช้ตัวย่อนำหน้าชื่อตัวแปร

เพราะว่า Autocomplete สามารถบ่งบอกชนิดของตัวแปรได้อยู่แล้วเราไม่ควรเขียน iNumber หรือ strName เป็นต้น

# การเรียงส่วนหัวของไฟล์

เพื่อที่จะให้ส่วนของการ import ไฟล์ต่างๆอ่านได้ง่าย เราจึงควรจะเรียงลำดับตามนี้
และแบ่งส่วนแต่ละส่วนคั่นด้วยบรรทัดว่าง

# ควร เรียงลำดับ dart: ขึ้นก่อนเป็นอันดับแรก

import 'dart:async';
import 'dart:html';

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

# ควร เรียงลำดับ package: ขึ้นก่อนการ import แบบ relative

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'util.dart';

# แนะนำ ให้เรียงลำดับ package: ที่มาจากภายนอกก่อน

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'package:my_package/util.dart';

# ควร เอา export ไว้ท้ายสุดหลังจาก import ทุกอัน

import 'src/error.dart';
import 'src/foo_bar.dart';

export 'src/error.dart';

# ควร เรียงลำดับในแต่ละส่วนตามลำดับตัวอักษร

import 'package:bar/bar.dart';
import 'package:foo/foo.dart';

import 'foo.dart';
import 'foo/foo.dart';

# การจัดรูปแบบโค้ด

เหมือนกับภาษาอื่นๆ Dart ไม่ได้สนใจบรรทัดว่าง หรือช่องว่าง แต่ว่าคนเขียนโปรแกรมก็ยังเห็นอยู่
การใส่การเว้นบรรทัด หรือเว้นวรรคจะช่วยให้โค้ดเราอ่านได้ง่ายขึ้น

# ควร ใช้ dartfmt ในการจัดโค้ด

dartfmt เป็นตัวช่วยในการจัดโค้ดให้เราได้อย่างสะดวกสบายมากๆครับ แต่ก็จะมีบางกรณีที่มันก็ช่วยเราไม่ได้เหมือนกัน เราจึงต้องช่วยตัวเองกันไป ถ้าใช้ VSCode สามารถใช้ settings ด้านล่างได้ครับ

{
  ...
  "[dart]": {
    "editor.tabSize": 2,
    "editor.insertSpaces": true,
    "editor.detectIndentation": false,
    "editor.formatOnSave": true,
    "editor.rulers": [80],
  }
  ...
}

# คิดก่อน ให้ dartfmt แก้โค้ด

dartfmt ช่วยให้โค้ดเราสวยขึ้นได้จริง แต่ถ้าช่วยไม่ได้ บางทีเราอาจจะต้องเปลี่ยนวิธีการเขียน เช่น โค้ดบางอย่างซับซ้อนเกินไป มีการใช้ Operator ยุ่งยากไม่เหมาะสม

# หลีกเลี่ยง การเขียนโค้ดแต่ละบรรทัดยาวเกิน 80 ตัวอักษร

การที่โค้ดแต่ละบรรทัดยาวเป็นพรืดๆ บางครั้งมันก็ทำให้โค้ดอ่านยากขึ้นเช่นกัน
ในบางครั้งเราตั้งชื่อตัวแปรยาวเกินไปก็อาจจะต้องคิดก่อนว่าเราตั้งชื่อยาวเกินความจำเป็นหรือไม่ สามารถลดคำลงได้หรือไม่

ยกเว้น URL หรือ ชื่อไฟล์ เราสามารถปล่อยให้ยาวเกิน 80 ตัวได้ เพื่อให้ง่ายต่อการค้นหา ยกเว้น String ที่มีหลายบรรทัด

# ควร ใส่ปีกกา {} เสมอๆในการทำงานประเภท if-else, for, while, อื่นๆ

เพื่อหลีกเลี่ยงปัญหาบางอย่าง เช่น การจับคู่ if-else ผิดพลาด

if (isWeekDay) {
  print('Bike to work!');
} else {
  print('Go dancing or read a book!');
}

ยกเว้น if ที่ไม่มี else และมีความยาวโค้ดไม่มากนัก

if (arg == null) return defaultValue;

แต่ถ้ายาวก็ขึ้นบรรทัดใหม่แล้วปิดด้วย {}

if (overflowChars != other.overflowChars) {
  return overflowChars < other.overflowChars;
}
อัปเดตเมื่อ: 1 ปีที่แล้ว