مرحبًا بالعالم

يمكنك العثور على كل كود هذا الفصل هنا

من التقاليد أن يكون أول برنامج تكتبه بأي لغة جديدة هو Hello, World.

  • أنشئ مجلدًا في أي مكان تريده
  • ضع داخله ملفًا جديدًا اسمه hello.go واكتب فيه الكود التالي
package main

import "fmt"

func main() {
	fmt.Println("Hello, world")
}

ولتشغيله اكتب go run hello.go.

كيف يعمل هذا؟

عند كتابة برنامج في Go، سيكون لديك حزمة main معرَّفة بداخلها دالة main. والحزم (packages) هي طريقة لتجميع كود Go المرتبط ببعضه.

كلمة func المفتاحية تعرّف دالة لها اسم وجسم.

وبكتابة import "fmt" نستورد حزمة تحتوي على الدالة Println التي نستخدمها للطباعة.

كيف نكتب اختبارًا؟

كيف يمكن اختبار هذا؟ من الجيد فصل كود “المجال” (domain) عن العالم الخارجي (الآثار الجانبية، side-effects). فالطباعة عبر fmt.Println أثر جانبي (كتابة إلى stdout)، بينما النص الذي نرسله هو مجالنا.

لذا دعنا نفصل هذه الاهتمامات ليكون الاختبار أسهل.

package main

import "fmt"

func Hello() string {
	return "Hello, world"
}

func main() {
	fmt.Println(Hello())
}

لقد أنشأنا دالة جديدة بـ func، لكننا هذه المرة أضفنا كلمة مفتاحية أخرى إلى التعريف هي string. وهذا يعني أن الدالة تُرجع string.

الآن أنشئ ملفًا جديدًا اسمه hello_test.go حيث سنكتب اختبارًا لدالة Hello.

package main

import "testing"

func TestHello(t *testing.T) {
	got := Hello()
	want := "Hello, world"

	if got != want {
		t.Errorf("got %q want %q", got, want)
	}
}

ماذا عن وحدات Go (modules)؟

الخطوة التالية هي تشغيل الاختبارات. اكتب go test في الطرفية. إذا نجحت الاختبارات، فأنت على الأرجح تستخدم إصدارًا قديمًا من Go. أما إذا كنت تستخدم Go 1.16 أو أحدث، فالاختبارات غالبًا لن تعمل، وسترى رسالة خطأ كهذه في الطرفية:

$ go test
go: cannot find main module; see 'go help modules'

فما المشكلة؟ بكلمة واحدة: الوحدات. لحسن الحظ، الحل سهل. اكتب go mod init example.com/hello في طرفيتك. سينشئ ذلك ملفًا جديدًا بهذا المحتوى:

module example.com/hello

go 1.16

يخبر هذا الملف أدوات go بمعلومات أساسية عن كودك. ولو كنت تخطط لتوزيع تطبيقك، فستضمّن فيه المكان الذي يمكن تنزيل الكود منه ومعلومات عن الاعتماديات. اسم الوحدة، example.com/hello، يشير عادةً إلى رابط يمكن العثور على الوحدة وتنزيلها منه. وللتوافق مع أدوات سنبدأ باستخدامها قريبًا، تأكد أن اسم وحدتك يحتوي على نقطة في مكان ما، مثل النقطة في ‎.com‎ في example.com/hello. في الوقت الحالي، ملف وحدتك مختصر، ويمكنك تركه كذلك. ولمعرفة المزيد عن الوحدات، يمكنك مراجعة المرجع في توثيق Golang. ويمكننا الآن العودة إلى الاختبار وتعلّم Go، لأن الاختبارات ينبغي أن تعمل حتى على Go 1.16.

في الفصول القادمة، ستحتاج إلى تشغيل go mod init SOMENAME في كل مجلد جديد قبل تشغيل أوامر مثل go test أو go build.

ومن الجدير التوضيح أن SOMENAME، أي اسم الوحدة، لا علاقة له بـ package main (التي يعلنها كل ملف .go في هذا الكتاب حتى الآن في أوله). فاسم الوحدة مجرد معرّف لمشروعك ككل؛ لا يجب أن يكون main، وستعمل go run وgo test وgo build بشكل صحيح مع أي اسم تختاره، طالما شغّلتها من داخل المجلد نفسه.

العودة إلى الاختبار

شغّل go test في طرفيتك. من المفترض أن ينجح الاختبار! وللتأكد، جرّب كسره عن قصد بتغيير نص want.

ولاحظ أنك لم تحتج إلى الاختيار بين أطر اختبار متعددة ثم معرفة كيفية تثبيتها. كل ما تحتاجه مدمج في اللغة نفسها، والصياغة هي نفسها صياغة بقية الكود الذي ستكتبه.

كتابة الاختبارات

كتابة اختبار تشبه كتابة دالة، مع بضعة قواعد:

  • يجب أن يكون في ملف باسم مثل xxx_test.go
  • يجب أن تبدأ دالة الاختبار بكلمة Test
  • تأخذ دالة الاختبار وسيطًا واحدًا فقط هو t *testing.T
  • لاستخدام نوع *testing.T، تحتاج إلى import "testing"، كما فعلنا مع fmt في الملف الآخر

يكفي الآن أن تعرف أن المتغير t من النوع *testing.T هو “خطافك” إلى إطار الاختبار، لتتمكن من أشياء مثل t.Fail() عندما تريد إفشال الاختبار.

وقد غطّينا بعض الموضوعات الجديدة:

‏if

جملة if في Go تشبه نظيراتها في لغات البرمجة الأخرى إلى حد كبير.

تعريف المتغيرات

نعرّف بعض المتغيرات بالصياغة varName := value، ما يتيح لنا إعادة استخدام بعض القيم في اختبارنا لتحسين القراءة.

‏t.Errorf

نستدعي هنا الدالة (method) Errorf على المتغير t، وهي تطبع رسالة وتفشل الاختبار. والحرف f اختصار لكلمة format، إذ يسمح لنا ببناء نص تُدرَج فيه القيم مكان العناصر البديلة %q. وعندما تفشل الاختبار سيتضح لك كيف يعمل ذلك.

ويمكنك قراءة المزيد عن نصوص العناصر البديلة في توثيق fmt. وفي الاختبارات يكون %q مفيدًا جدًا لأنه يحيط قيمك بعلامات اقتباس مزدوجة.

وسنستكشف لاحقًا الفرق بين الـ methods والـ functions.

توثيق Go

من ميزات Go التي تريحك أيضًا التوثيق. لقد رأينا للتو توثيق حزمة fmt على موقع عرض الحزم الرسمي، وتوفر Go كذلك طرقًا للوصول السريع إلى التوثيق دون اتصال بالإنترنت.

فـ Go تمتلك أداة مدمجة اسمها doc، تتيح لك فحص أي حزمة مثبتة على نظامك، أو الوحدة التي تعمل عليها حاليًا. ولعرض التوثيق نفسه الخاص بأفعال الطباعة:

$ go doc fmt
package fmt // import "fmt"

Package fmt implements formatted I/O with functions analogous to C's printf and
scanf. The format 'verbs' are derived from C's but are simpler.

# Printing

The verbs:

General:

    %v	the value in a default format
    	when printing structs, the plus flag (%+v) adds field names
    %#v	a Go-syntax representation of the value
    %T	a Go-syntax representation of the type of the value
    %%	a literal percent sign; consumes no value
...

أما الأداة الثانية لعرض التوثيق فهي أمر pkgsite، وهو الذي يشغّل موقع عرض الحزم الرسمي. يمكنك تثبيت pkgsite بالأمر go install golang.org/x/pkgsite/cmd/pkgsite@latest ثم تشغيله بـ pkgsite -open .. وسيقوم أمر التثبيت في Go بتنزيل ملفات المصدر من ذلك المستودع وبنائها في ملف تنفيذي. وفي التثبيت الافتراضي لـ Go سيكون ذلك الملف التنفيذي في $HOME/go/bin على Linux وmacOS، وفي %USERPROFILE%\go\bin على Windows. وإذا لم تكن قد أضفت هذين المسارين إلى متغير PATH بعد، فرُبما تريد فعل ذلك ليسهل عليك تشغيل الأدوات المثبتة عبر go.

والغالبية العظمى من المكتبة القياسية موثقة توثيقًا ممتازًا مع أمثلة. ويستحق أن تنتقل إلى http://localhost:8080/testing لترى ما هو متاح لك.

مرحبًا بك أنت

بعد أن أصبح لدينا اختبار، يمكننا تطوير برمجيتنا بأمان.

في المثال الأخير كتبنا الاختبار بعد كتابة الكود، حتى تحصل على مثال لكيفية كتابة اختبار وتعريف دالة. ومن هذه النقطة فصاعدًا، سنكتب الاختبارات أولًا.

متطلبنا التالي هو أن نحدد لمن نوجه التحية.

لنبدأ بتوثيق هذا المتطلب في اختبار. هذه هي أساسيات التطوير الموجه بالاختبار، وهي التي تتيح لنا التأكد أن اختبارنا يختبر فعلًا ما نريده. فعندما تكتب الاختبارات بأثر رجعي، يوجد خطر أن يظل اختبارك ناجحًا حتى لو لم يعمل الكود كما تقصد.

package main

import "testing"

func TestHello(t *testing.T) {
	got := Hello("Chris")
	want := "Hello, Chris"

	if got != want {
		t.Errorf("got %q want %q", got, want)
	}
}

شغّل الآن go test، وستظهر لك أخطاء في الترجمة (compilation error).

./hello_test.go:6:18: too many arguments in call to Hello
    have (string)
    want ()

عند استخدام لغة ذات أنواع ثابتة مثل Go، من المهم أن تصغي إلى المترجم. فالمترجم يفهم كيف يجب أن تتلاءم أكوادك وتعمل، ما يعفيك من عناء ذلك.

في هذه الحالة يخبرك المترجم بما عليك فعله للمتابعة، وهو أن نعدّل الدالة Hello لتقبل وسيطًا.

عدّل الدالة Hello لتقبل وسيطًا من نوع string.

func Hello(name string) string {
	return "Hello, world"
}

وإذا حاولت تشغيل اختباراتك مرة أخرى، سيفشل hello.go في الترجمة لأنك لا تمرر وسيطًا. مرّر "world" ليعمل الكود.

func main() {
	fmt.Println(Hello("world"))
}

الآن عند تشغيل الاختبارات، من المفترض أن ترى شيئًا كهذا:

hello_test.go:10: got 'Hello, world' want 'Hello, Chris''

أصبح لدينا في النهاية برنامج يعمل، لكنه لا يحقق متطلبنا حسب الاختبار.

لنجعل الاختبار ينجح باستخدام وسيط الاسم ودمجه مع النص Hello,.

func Hello(name string) string {
	return "Hello, " + name
}

عند تشغيل الاختبارات، من المفترض أن تنجح الآن. وكما جرت العادة في دورة التطوير الموجه بالاختبار، ينبغي أن نقوم الآن بإعادة الهيكلة (refactor).

ملاحظة عن التحكم في الإصدارات

في هذه المرحلة، إذا كنت تستخدم نظام تحكم في الإصدارات (وأنت مُطالب بذلك!) فسأسجّل الكود كما هو في commit. فأصبح لدينا برنامج يعمل ومدعوم باختبار.

لكنني لن أنشر ذلك إلى main، لأنني أخطط لإعادة الهيكلة بعد قليل. ومن الجيد أن تسجّل عند هذه النقطة، حتى إذا وقعت في مشكلة أثناء إعادة الهيكلة يمكنك دائمًا الرجوع إلى النسخة العاملة.

ليس هناك الكثير لنعيد هيكلته هنا، لكننا سنقدّم ميزة لغوية أخرى: الثوابت (constants).

الثوابت (Constants)

تُعرَّف الثوابت هكذا:

const englishHelloPrefix = "Hello, "

ويمكننا الآن إعادة هيكلة كودنا.

const englishHelloPrefix = "Hello, "

func Hello(name string) string {
	return englishHelloPrefix + name
}

بعد إعادة الهيكلة، شغّل اختباراتك مجددًا للتأكد أنك لم تكسر شيئًا.

ومن الجدير التفكير في إنشاء ثوابت لتوضيح معنى القيم، وأحيانًا لتحسين الأداء.

مرحبًا بالعالم… من جديد

المتطلب التالي هو أنه عندما تُستدعى الدالة بنص فارغ، يكون الناتج الافتراضي “Hello, World” بدلًا من “Hello, “.

ابدأ بكتابة اختبار فاشل جديد.

func TestHello(t *testing.T) {
	t.Run("saying hello to people", func(t *testing.T) {
		got := Hello("Chris")
		want := "Hello, Chris"

		if got != want {
			t.Errorf("got %q want %q", got, want)
		}
	})
	t.Run("say 'Hello, World' when an empty string is supplied", func(t *testing.T) {
		got := Hello("")
		want := "Hello, World"

		if got != want {
			t.Errorf("got %q want %q", got, want)
		}
	})
}

هنا نقدّم أداة أخرى في ترسانة اختباراتنا: الاختبارات الفرعية (subtests). فمن المفيد أحيانًا تجميع الاختبارات حول “شيء” واحد ثم كتابة اختبارات فرعية تصف سيناريوهات مختلفة.

ومن مزايا هذا الأسلوب أنك تستطيع إعداد كود مشترك يُستخدم في بقية الاختبارات.

وبينما لدينا اختبار فاشل، لنصلح الكود باستخدام if.

const englishHelloPrefix = "Hello, "

func Hello(name string) string {
	if name == "" {
		name = "World"
	}
	return englishHelloPrefix + name
}

إذا شغّلنا اختباراتنا، ينبغي أن نجد أنها تحقق المتطلب الجديد ولم نكسر الوظيفة الأخرى دون قصد.

من المهم أن تكون اختباراتك مواصفات واضحة لما ينبغي أن يفعله الكود. لكن يوجد كود مكرر عند التحقق من أن الرسالة هي ما نتوقعه.

فإعادة الهيكلة ليست فقط لكود الإنتاج!

وبعد أن أصبحت الاختبارات تنجح، يمكننا بل ينبغي أن نعيد هيكلة اختباراتنا.

func TestHello(t *testing.T) {
	t.Run("saying hello to people", func(t *testing.T) {
		got := Hello("Chris")
		want := "Hello, Chris"
		assertCorrectMessage(t, got, want)
	})

	t.Run("empty string defaults to 'world'", func(t *testing.T) {
		got := Hello("")
		want := "Hello, World"
		assertCorrectMessage(t, got, want)
	})

}

func assertCorrectMessage(t testing.TB, got, want string) {
	t.Helper()
	if got != want {
		t.Errorf("got %q want %q", got, want)
	}
}

ماذا فعلنا هنا؟

أعدنا هيكلة التحقق (assertion) في دالة جديدة. وهذا يقلل التكرار ويحسّن قراءة اختباراتنا. ونحتاج إلى تمرير t *testing.T حتى نستطيع إخبار كود الاختبار بأن يفشل عند الحاجة.

وفي دوال المساعدة، من الجيد أن تقبل testing.TB، وهي واجهة (interface) تحققها كل من *testing.T و*testing.B، لتستطيع استدعاء دوال المساعدة من اختبار أو من قياس أداء (benchmark) (لا تقلق إن كانت كلمات مثل “interface” بلا معنى عندك الآن، فسنغطيها لاحقًا).

ويُحتاج t.Helper() لإخبار مجموعة الاختبارات بأن هذه الدالة مساعدة. وبذلك، عند فشلها سيكون رقم السطر المُبلَّغ عنه عند استدعاء الدالة لا داخل دالة المساعدة، ما يساعد المطورين الآخرين على تتبع المشكلات بسهولة أكبر. وإذا لم تفهم ذلك بعد، علّق الكود، وأفشل اختبارًا، ولاحظ مخرجات الاختبار. والتعليقات طريقة رائعة لإضافة معلومات إلى كودك، أو في هذه الحالة طريقة سريعة لجعل المترجم يتجاهل سطرًا. ويمكنك تعليق كود t.Helper() بإضافة شرطتين مائلتين // في بداية السطر، وسترى السطر يتحول إلى اللون الرمادي أو إلى لون مختلف عن بقية كودك ليشير إلى أنه أصبح تعليقًا.

وعندما يكون لديك أكثر من وسيط من النوع نفسه (نصان في حالتنا) فبدلًا من (got string, want string) يمكنك اختصارها إلى (got, want string).

العودة إلى التحكم في الإصدارات

بعد أن رضينا عن الكود، سأعدّل الـ commit السابق (amend) بحيث لا نُسجّل إلا النسخة الجميلة من كودنا مع اختباره.

الانضباط

لنستعرض الدورة مرة أخرى:

  • اكتب اختبارًا
  • اجعل المترجم يمر
  • شغّل الاختبار، وتأكد أنه يفشل، وافحص أن رسالة الخطأ ذات معنى
  • اكتب كودًا كافيًا لنجاح الاختبار
  • أعد الهيكلة

قد يبدو هذا مُملًا على السطح، لكن الالتزام بحلقة التغذية الراجعة مهم.

فهو لا يضمن فقط أن لديك اختبارات ذات صلة، بل يساعد أيضًا على تصميم برمجيات جيدة عبر إعادة الهيكلة مع أمان الاختبارات.

ورؤية الاختبار يفشل فحص مهم لأنه يتيح لك رؤية شكل رسالة الخطأ. فبصفتك مطورًا قد يكون من الصعب جدًا العمل على قاعدة كود عندما لا تعطي الاختبارات الفاشلة فكرة واضحة عن المشكلة.

وبتأكيد أن اختباراتك سريعة وتهيئة أدواتك ليكون تشغيل الاختبارات بسيطًا، تستطيع الدخول في حالة من الانسياب (flow) أثناء كتابة كودك.

وبعدم كتابة الاختبارات، فأنت تلتزم بفحص كودك يدويًا بتشغيل برنامجك، ما يكسر حالة الانسياب لديك. ولن توفر على نفسك أي وقت، خصوصًا على المدى الطويل.

واصل! متطلبات أكثر

يا إلهي، لدينا متطلبات أكثر. نحتاج الآن إلى دعم وسيط ثانٍ يحدد لغة التحية. وإذا مُرّرت لغة لا نعرفها، فالافتراضي هو الإنجليزية.

ينبغي أن نكون واثقين أننا نستطيع بسهولة استخدام التطوير الموجه بالاختبار لإنجاز هذه الوظيفة!

اكتب اختبارًا لمستخدم يمرر الإسبانية. وأضفه إلى المجموعة الحالية.

	t.Run("in Spanish", func(t *testing.T) {
		got := Hello("Elodie", "Spanish")
		want := "Hola, Elodie"
		assertCorrectMessage(t, got, want)
	})

تذكّر ألا تغش! الاختبار أولًا. عند محاولة تشغيل الاختبار، ينبغي أن يشتكي المترجم لأنك تستدعي Hello بوسيطين لا بوسيط واحد.

./hello_test.go:27:19: too many arguments in call to Hello
    have (string, string)
    want (string)

أصلح مشكلات الترجمة بإضافة وسيط نصي آخر إلى Hello.

func Hello(name string, language string) string {
	if name == "" {
		name = "World"
	}
	return englishHelloPrefix + name
}

وعند محاولة تشغيل الاختبار مرة أخرى، سيشكو من عدم تمرير عدد كافٍ من الوسائط إلى Hello في اختباراتك الأخرى وفي hello.go.

./hello.go:15:19: not enough arguments in call to Hello
    have (string)
    want (string, string)

أصلح ذلك بتمرير نصوص فارغة. الآن ينبغي أن تترجم كل اختباراتك وتنجح، ما عدا السيناريو الجديد.

hello_test.go:29: got 'Hello, Elodie' want 'Hola, Elodie'

يمكننا استخدام if هنا للتحقق أن اللغة تساوي “Spanish”، وإذا كان الأمر كذلك نغيّر الرسالة.

func Hello(name string, language string) string {
	if name == "" {
		name = "World"
	}

	if language == "Spanish" {
		return "Hola, " + name
	}
	return englishHelloPrefix + name
}

من المفترض أن تنجح الاختبارات الآن.

وحان وقت إعادة الهيكلة. ينبغي أن ترى بعض المشكلات في الكود: نصوص “سحرية” (magic strings) بعضها مكرر. جرّب إعادة هيكلته بنفسك، ومع كل تغيير تأكد من إعادة تشغيل الاختبارات لتعرف أن إعادة الهيكلة لا تكسر شيئًا.

	const spanish = "Spanish"
	const englishHelloPrefix = "Hello, "
	const spanishHelloPrefix = "Hola, "

	func Hello(name string, language string) string {
		if name == "" {
			name = "World"
		}

		if language == spanish {
			return spanishHelloPrefix + name
		}
		return englishHelloPrefix + name
	}

الفرنسية

  • اكتب اختبارًا يتحقق أنك إذا مرّرت "French" فستحصل على "Bonjour, "
  • شاهده يفشل، وتأكد أن رسالة الخطأ سهلة القراءة
  • قم بأصغر تغيير منطقي في الكود

وربما كتبت شيئًا يشبه هذا تقريبًا:

func Hello(name string, language string) string {
	if name == "" {
		name = "World"
	}

	if language == spanish {
		return spanishHelloPrefix + name
	}
	if language == french {
		return frenchHelloPrefix + name
	}
	return englishHelloPrefix + name
}

‏switch

عندما يكون لديك الكثير من جمل if التي تفحص قيمة معينة، فمن الشائع استخدام جملة switch بدلًا منها. ويمكننا استخدام switch لإعادة هيكلة الكود ليكون أسهل قراءة وأكثر قابلية للتوسع إذا أردنا دعم لغات إضافية لاحقًا.

func Hello(name string, language string) string {
	if name == "" {
		name = "World"
	}

	prefix := englishHelloPrefix

	switch language {
	case spanish:
		prefix = spanishHelloPrefix
	case french:
		prefix = frenchHelloPrefix
	}

	return prefix + name
}

لاحظ أننا استخدمنا := مرة واحدة مع prefix (لتعريف متغير جديد وإعطائه قيمة ابتدائية)، ثم استخدمنا = المجردة في كل مكان آخر يتغير فيه، سواء مع name في الأعلى أو prefix داخل switch. فالـ := هي تعريف المتغير المختصر في Go، وهي تنشئ متغيرًا جديدًا. أما = فهي إسناد عادي، وتغيّر قيمة متغير موجود بالفعل (name موجود أصلًا كبارامتر، وprefix عُرّف قبل سطرين بـ :=). واستخدام := مع متغير موجود بالفعل في النطاق نفسه، أو = مع متغير غير موجود بعد، خطأ في الترجمة.

اكتب اختبارًا يضيف تحية بلغة من اختيارك، وسترى كم هو بسيط توسيع دالتنا المذهلة.

إعادة…هيكلة…أخيرة؟

قد تقول إن دالتنا أصبحت كبيرة قليلًا. وأبسط إعادة هيكلة لذلك هي استخراج بعض الوظائف إلى دالة أخرى.


const (
	spanish = "Spanish"
	french  = "French"

	englishHelloPrefix = "Hello, "
	spanishHelloPrefix = "Hola, "
	frenchHelloPrefix  = "Bonjour, "
)

func Hello(name string, language string) string {
	if name == "" {
		name = "World"
	}

	return greetingPrefix(language) + name
}

func greetingPrefix(language string) (prefix string) {
	switch language {
	case french:
		prefix = frenchHelloPrefix
	case spanish:
		prefix = spanishHelloPrefix
	default:
		prefix = englishHelloPrefix
	}
	return
}

بعض المفاهيم الجديدة:

  • في توقيع الدالة جعلنا القيمة المُرجعة مُسمّاة (prefix string).
  • وسيُنشئ ذلك متغيرًا اسمه prefix داخل دالتك.
    • وسيُسند إليه القيمة “الصفرية” (zero value)، وهي تعتمد على النوع، فمثلًا قيم int الصفرية هي 0، وللنصوص string هي "".
      • ويمكنك إرجاع ما تم إسناده إليه بمجرد كتابة return بدلًا من return prefix.
    • وسيظهر ذلك في توثيق Go لدالتك، فيوضّح قصد كودك أكثر.
  • أما default في جملة switch فيُنتقل إليها إذا لم تطابق أي من جمل case الأخرى.
  • ويبدأ اسم الدالة بحرف صغير. ففي Go تبدأ الدوال العامة (public) بحرف كبير، والخاصة (private) بحرف صغير. ونحن لا نريد كشف تفاصيل الخوارزمية للعالم، لذا جعلنا هذه الدالة خاصة.
  • كما يمكننا تجميع الثوابت في كتلة بدلًا من تعريف كل منها في سطر منفصل. ولأجل القراءة، من الجيد وضع سطر فاصل بين مجموعات الثوابت المرتبطة.

الخلاصة

من كان يتخيل أن Hello, world يمكن أن يعلّمك كل هذا؟

بحلول الآن ينبغي أن يكون لديك فهم لـ:

بعض صياغات Go حول

  • كتابة الاختبارات
  • تعريف الدوال، مع الوسائط وأنواع الإرجاع
  • ‏if وconst وswitch
  • تعريف المتغيرات والثوابت

عملية التطوير الموجه بالاختبار ولماذا هذه الخطوات مهمة

  • اكتب اختبارًا فاشلًا وشاهده يفشل، لنتأكد أننا كتبنا اختبارًا ذا صلة بمتطلباتنا، ورأينا أنه ينتج وصفًا سهل الفهم للفشل
  • اكتب أصغر قدر من الكود لجعله ينجح، لنعرف أن لدينا برنامجًا يعمل
  • ثم أعد الهيكلة، مدعومًا بأمان اختباراتنا، لتتأكد أن لدينا كودًا مصقولًا يسهل التعامل معه

في حالتنا هذه، انتقلنا من Hello() إلى Hello("name") ثم إلى Hello("name", "French") بخطوات صغيرة سهلة الفهم.

بالطبع هذا بسيط مقارنة ببرمجيات “العالم الحقيقي”، لكن المبادئ تبقى صحيحة. فالتطوير الموجه بالاختبار مهارة تحتاج إلى تدريب لتتطور، لكن بتقسيم المشكلات إلى مكونات أصغر يمكنك اختبارها، سيكون كتابة البرمجيات أسهل بكثير.