Apakah penggunaan blok lingkup internal dalam gaya fungsi buruk?

10

Ada beberapa (sangat jarang) kasus di mana ada risiko:

  • menggunakan kembali variabel yang tidak dimaksudkan untuk digunakan kembali (lihat contoh 1),

  • atau menggunakan variabel bukan yang lain, tutup semantik (lihat contoh 2).

Contoh 1:

var data = this.InitializeData();
if (this.IsConsistent(data, this.state))
{
    this.ETL.Process(data); // Alters original data in a way it couldn't be used any longer.
}

// ...

foreach (var flow in data.Flows)
{
    // This shouldn't happen: given that ETL possibly altered the contents of `data`, it is
    // not longer reliable to use `data.Flows`.
}

Contoh 2:

var userSettingsFile = SettingsFiles.LoadForUser();
var appSettingsFile = SettingsFiles.LoadForApp();

if (someCondition)
{
    userSettingsFile.Destroy();
}

userSettingsFile.ParseAndApply(); // There is a mistake here: `userSettingsFile` was maybe
                                  // destroyed. It's `appSettingsFile` which should have
                                  // been used instead.

Risiko ini dapat dikurangi dengan memperkenalkan ruang lingkup:

Contoh 1:

// There is no `foreach`, `if` or anything like this before `{`.

{
    var data = this.InitializeData();
    if (this.IsConsistent(data, this.state))
    {
        this.ETL.Process(data);
    }
}

// ...

// A few lines later, we can't use `data.Flows`, because it doesn't exist in this scope.

Contoh 2:

{
    var userSettingsFile = SettingsFiles.LoadForUser();

    if (someCondition)
    {
        userSettingsFile.Destroy();
    }
}

{
    var appSettingsFile = SettingsFiles.LoadForApp();

    // `userSettingsFile` is out of scope. There is no risk to use it instead of
    // `appSettingsFile`.
}

Apakah itu terlihat salah? Apakah Anda akan menghindari sintaksis seperti itu? Apakah sulit dipahami oleh pemula?

Arseni Mourzenko
sumber
7
Bisakah Anda berargumen bahwa setiap "ruang lingkup" independen bukannya harus menjadi metode atau fungsinya sendiri?
Dan Pichelman
Saya akan mengatakan "sering" tidak dilaksanakan sebaik mungkin (tapi mungkin bukan masalah "desain"). Kadang-kadang dengan desain, itu tidak dapat dihindari (misalnya pengecualian / pelingkupan sumber daya).
JustinC

Jawaban:

35

Jika fungsi Anda begitu lama sehingga Anda tidak dapat mengenali efek samping yang tidak diinginkan atau penggunaan kembali variabel secara ilegal, maka sekarang saatnya untuk membaginya dalam fungsi yang lebih kecil - yang membuat ruang lingkup internal tidak ada gunanya.

Untuk mendukung hal ini oleh beberapa pengalaman pribadi: beberapa tahun yang lalu saya mewarisi proyek warisan C ++ dengan ~ 150 ribu baris kode, dan berisi beberapa metode yang menggunakan teknik ini. Dan coba tebak - semua metode itu terlalu panjang. Ketika kami refactored sebagian besar kode itu, metode menjadi lebih kecil dan lebih kecil, dan saya cukup yakin tidak ada metode "ruang lingkup internal" yang tersisa lagi; mereka sama sekali tidak dibutuhkan.

Doc Brown
sumber
4
Tetapi mengapa itu buruk? Memiliki banyak fungsi bernama juga membingungkan.
Kris Van Bael
1
+1 Tepat, jika Anda membutuhkan ruang lingkup, kemungkinan Anda melakukan tindakan tertentu yang dapat diekstraksi ke suatu fungsi. Kris, ini bukan tentang membuat banyak dan banyak fungsi, itu ketika kasus-kasus ini terjadi (di mana ruang lingkup satu blok mungkin bertentangan dengan yang lain) yang biasanya fungsi harus digunakan. Saya melihat ini dalam bahasa lain (yaitu JavaScript, dengan fungsi lama IIFE alih-alih polos) sepanjang waktu juga.
Benjamin Gruenbaum
10
@KrisVanBael: "Memiliki banyak fungsi bernama juga membingungkan" - jika Anda menggunakan nama deskriptif, yang terjadi adalah sebaliknya. Membuat fungsi terlalu besar adalah alasan paling atas bagaimana kode menjadi sulit untuk dipelihara, dan bahkan lebih sulit untuk diperluas.
Doc Brown
2
Jika ada begitu banyak fungsi yang menamakannya dengan jelas menjadi masalah, mungkin beberapa dari mereka dapat digulung menjadi tipe baru karena mereka mungkin memiliki independensi yang signifikan dari tubuh fungsi aslinya. Beberapa mungkin berhubungan sangat dekat sehingga mereka bisa dihilangkan. Tiba-tiba, tidak ada begitu banyak fungsi.
JustinC
3
Masih belum yakin. Seringkali fungsi lama memang buruk. Tetapi mengatakan bahwa setiap kebutuhan untuk ruang lingkup memerlukan fungsi terpisah terlalu hitam & putih untuk saya.
Kris Van Bael
3

Jauh lebih mudah bagi pemula (dan programmer mana pun) untuk memikirkan:

  • tidak menggunakan variabel yang tidak relevan

daripada memikirkan:

  • menambahkan struktur kode yang bertujuan mencegah dirinya dari tidak menggunakan variabel yang tidak relevan.

Selain itu, dari sudut pandang pembaca, blok seperti itu tidak memiliki peran yang jelas: menghapusnya tidak berdampak pada eksekusi. Pembaca dapat menggaruk kepalanya mencoba menebak apa yang ingin dicapai oleh pembuat kode.

mouviciel
sumber
2

Menggunakan ruang lingkup secara teknis benar. Tetapi jika Anda ingin membuat kode Anda lebih mudah dibaca maka Anda harus mengekstrak bagian itu dalam metode lain dan memberikan arti nama lengkap. Dengan cara ini Anda bisa memberi ruang lingkup variabel Anda dan juga memberi nama tugas Anda.

DeveloperArnab
sumber
0

Saya setuju bahwa menggunakan kembali variabel lebih sering daripada tidak berbau kode. Mungkin kode semacam itu harus di refactored dalam blok-blok yang lebih kecil dan mandiri.

Ada satu skenario khusus, OTOH, di C #, ketika mereka cenderung muncul - yaitu ketika menggunakan konstruksi kasus saklar. Situasi dijelaskan dengan sangat baik dalam: C # Beralih pernyataan dengan / tanpa kurung keriting ... apa bedanya?

Dejan Stanič
sumber