Apa cara yang masuk akal untuk membuat tata letak proyek Go [closed]

113

Saya memiliki proyek berjalan yang mulai menjadi lebih kompleks, dan ingin meletakkan sistem file sedemikian rupa untuk mengurangi rasa sakit.

Apakah ada beberapa contoh bagus di luar sana tentang apa yang masuk akal?

aussiegeek
sumber

Jawaban:

132

Pembaruan Mei 2013: dokumentasi resmi ada di bagian " Organisasi kode "

Kode Go harus disimpan di dalam ruang kerja .
Ruang kerja adalah hierarki direktori dengan tiga direktori di akarnya:

  • src berisi file sumber Go yang diatur ke dalam paket (satu paket per direktori),
  • pkg berisi objek paket, dan
  • bin berisi perintah yang dapat dieksekusi.

The go toolmembangun paket source dan menginstal binari yang dihasilkan ke pkgdan bindirektori.

The srcsubdirektori biasanya berisi beberapa repositori kontrol versi (seperti untuk Git atau Mercurial) yang melacak perkembangan satu atau lebih paket source.

bin/
    streak                         # command executable
    todo                           # command executable
pkg/
    linux_amd64/
        code.google.com/p/goauth2/
            oauth.a                # package object
        github.com/nf/todo/
            task.a                 # package object
src/
    code.google.com/p/goauth2/
        .hg/                       # mercurial repository metadata
        oauth/
            oauth.go               # package source
            oauth_test.go          # test source

Pembaruan Juli 2014: lihat " Menyusun Aplikasi di Go " dari Ben Johnson

Artikel itu berisi tip seperti:

Pisahkan biner Anda dari aplikasi Anda

menggabungkan main.gofile dan logika aplikasi saya dalam paket yang sama memiliki dua konsekuensi:

  • Itu membuat aplikasi saya tidak dapat digunakan sebagai perpustakaan.
  • Saya hanya dapat memiliki satu aplikasi biner.

Cara terbaik yang saya temukan untuk memperbaikinya adalah dengan menggunakan cmddirektori " " dalam proyek saya di mana setiap subdirektorinya adalah biner aplikasi.

camlistore/
  cmd/
    camget/
      main.go
    cammount/
      main.go
    camput/
      main.go
    camtool/
      main.go

Pengembangan yang didorong oleh perpustakaan

Memindahkan main.gofile dari root memungkinkan Anda membangun aplikasi dari perspektif perpustakaan. Biner aplikasi Anda hanyalah klien perpustakaan aplikasi Anda.

Terkadang Anda mungkin ingin pengguna berinteraksi dengan berbagai cara sehingga Anda membuat banyak biner.
Misalnya, jika Anda memiliki adderpaket " " yang memungkinkan pengguna menambahkan nomor bersama-sama, Anda mungkin ingin merilis versi baris perintah serta versi web.
Anda dapat dengan mudah melakukan ini dengan mengatur proyek Anda seperti ini:

adder/
  adder.go
  cmd/
    adder/
      main.go
    adder-server/
      main.go

Pengguna dapat menginstal biner aplikasi "adder" Anda dengan "go get" menggunakan elipsis:

$ go get github.com/benbjohnson/adder/...

Dan voila, pengguna Anda telah menginstal " adder" dan " adder-server"!

Jangan tergila-gila dengan sub-paket

Biasanya jenis proyek saya semuanya sangat terkait sehingga lebih cocok dari sudut pandang kegunaan dan API.
Jenis ini juga dapat memanfaatkan pemanggilan unexported di antara mereka yang membuat API tetap kecil dan jelas.

  1. Kelompokkan jenis dan kode terkait menjadi satu di setiap file. Jika jenis dan fungsi Anda terorganisir dengan baik maka saya menemukan bahwa file cenderung antara 200 dan 500 SLOC. Ini mungkin terdengar banyak tapi saya merasa mudah dinavigasi. 1000 SLOC biasanya merupakan batas atas saya untuk satu file.
  2. Atur jenis yang paling penting di bagian atas file dan tambahkan jenis untuk mengurangi kepentingan di bagian bawah file.
  3. Setelah aplikasi Anda mulai mendapatkan di atas 10.000 SLOC, Anda harus mengevaluasi secara serius apakah itu dapat dipecah menjadi proyek yang lebih kecil.

Catatan: latihan terakhir tidak selalu baik:

Maaf, saya tidak setuju dengan praktik ini.
Memisahkan tipe ke file membantu manajemen kode, keterbacaan, pemeliharaan, kemampuan pengujian.
Ini juga dapat memastikan tanggung jawab tunggal dan mengikuti prinsip terbuka / tertutup…
Aturan untuk tidak mengizinkan ketergantungan melingkar adalah untuk memaksa kami memiliki struktur paket yang jelas.


(Alternatif Februari 2013, srchanya terkait )
Anda dapat menemukan tata letak klasik yang diilustrasikan dalam " Tata Letak Kode GitHub ":

Aplikasi dan kedua library tersebut ada di Github, masing-masing di repositori sendiri.
$GOPATHadalah root dari proyek - setiap repo Github Anda akan diperiksa di beberapa folder di bawah ini $GOPATH.

Tata letak kode Anda akan terlihat seperti ini:

$GOPATH/
    src/
        github.com/
            jmcvetta/
                useless/
                    .git/
                    useless.go
                    useless_test.go
                    README.md
                uselessd/
                    .git/
                    uselessd.go
                    uselessd_test.go
                    README.md

Setiap folder di bawah src/github.com/jmcvetta/adalah root dari git checkout yang terpisah.

Itu menarik beberapa kritik, di halaman reddit ini :

Saya sangat menyarankan untuk tidak menyusun repo seperti yang Anda miliki, itu akan merusak " go get", yang merupakan salah satu hal paling berguna tentang Go.
Jauh lebih baik untuk menulis kode Anda untuk orang yang tahu tentang Go, karena kemungkinan besar merekalah yang menyusunnya.
Dan bagi orang yang tidak, setidaknya mereka akan memahami bahasanya.

Letakkan paket utama di root repo.
Memiliki aset dalam subdirektori (untuk menjaga agar semuanya tetap rapi).
Simpan isi kode dalam sub-paket (jika ada yang ingin menggunakannya kembali di luar biner Anda).
Sertakan skrip pengaturan di root repo sehingga mudah ditemukan.

Ini masih hanya proses dua langkah untuk mengunduh, membangun, menginstal, dan mengatur .:

  • " go get <your repo path>": mengunduh dan memasang kode go, dengan subdirektori untuk aset
  • $GOPATH/<your repo path>/setup.sh: mendistribusikan aset ke tempat yang tepat dan menginstal layanan
VonC
sumber
15
Satu masalah (besar) setup.shadalah bahwa Go cukup lintas platform sedangkan skrip shell POSIX tidak.
kostix
Struktur jmcvetta tidak akan merusak go get, karena uselessd mengimpor tidak berguna, go get akan menginstal keduanya dengan go get ... / uselessd. Tetapi saya setuju bahwa jika tidak berguna adalah pustaka yang secara khusus dibuat untuk tidak berguna, lebih masuk akal untuk menyimpannya dalam satu repo git, sebagai subfolder atau saudara kandung.
mna
@PuerkitoBio Saya setuju. Pelatihan saya dalam kontrol versi dan manajemen berbasis komponen ( stackoverflow.com/a/933735/6309 ) membawa saya lebih banyak ke satu komponen per repo, karenanya merupakan bagian kedua dari jawaban ini.
VonC
7

Saya berasumsi bahwa dengan 'proyek' yang Anda maksud bukan paket Go tetapi perangkat lunak yang Anda kembangkan. Jika tidak, Anda bisa mendapatkan bantuan di sini dan di sini . Namun tidak jauh berbeda dengan menulis paket untuk Go: Gunakan paket, buat folder untuk setiap paket dan gabungkan paket-paket itu dalam aplikasi Anda.

Untuk membuat opini sendiri, Anda dapat melihat repositori Go yang sedang tren di github: https://github.com/trending/go . Contoh penting adalah cayley dan zeus .

Skema yang paling populer mungkin memiliki file Go utama dan banyak modul dan submodul di direktorinya sendiri. Jika Anda memiliki banyak file meta (dokumen, lisensi, template, ...), Anda mungkin ingin memasukkan kode sumber ke dalam subdirektori. Itulah yang saya lakukan sejauh ini.

nemo
sumber
@aussiegeek, saya bukan ahli Go, tapi saya berhasil menerapkan apa yang diusulkan nemo dalam kode saya sendiri - idenya adalah Anda dapat memiliki modul di bawah direktori proyek Anda, Anda hanya perlu merujuknya menggunakan awalan lengkap - relatif ke $GOPATH/srcatau menggunakan go getnama -tabel mereka .
kostix
doozerdbukanlah contoh yang baik, bahkan pengujiannya lemah.
Inanc Gumus
@InancGumus Saya mendorong Anda untuk menyarankan contoh yang lebih baik.
nemo
lihat ini dan ini .
Inanc Gumus
1

Ada pendekatan yang direkomendasikan dari penulis Golang yang menentukan bagaimana tata letak kode Anda agar bekerja paling baik dengan alat go dan untuk mendukung sistem kendali sumber

FigmentEngine
sumber
1
Begitulah tata letak $GOROOT, bukan kode di dalam src/<project>direktori.
docwhat