Apa cara yang bagus dan ringkas untuk menjelaskan bahaya pemrograman copy-paste kepada yang bukan pemrogram? [Tutup]


27

Saya mencari analogi atau metafora yang bagus yang bisa menggambarkan masalah pemrograman copy-paste untuk non-programmer. Saya kadang-kadang melakukan review kode / sistem untuk klien potensial, dan salah satu masalah umum yang saya lihat adalah sejumlah besar kode copy-paste di seluruh basis kode mereka. Ini adalah sesuatu yang secara rutin saya panggil di ulasan, dan setiap kali saya harus menjelaskan mengapa ini menjadi masalah (ini sangat sulit dengan klien yang tahu cukup banyak tentang pemrograman untuk memahami bahwa menggunakan kembali adalah hal yang baik, tetapi tidak cukup untuk memahami mengapa copy-paste bukanlah bentuk penggunaan kembali yang baik). Jelas, saya dapat (dan memang) menjelaskan masalah dalam hal pemeliharaan kode, tetapi akan menyenangkan untuk memiliki analogi yang baik dan ringkas untuk masalah ini yang akan menyentuh rumah dengan non-programmer. Bonus jika analoginya menggambarkan mengapa pencarian-dan-ganti bukanlah solusi yang efektif untuk masalah ini. Ada saran?

Hanya untuk memperjelas (berdasarkan jawaban Jaroslav di bawah) - Saya tidak berbicara tentang menggunakan cuplikan kode di sini; apa yang saya lihat (sering mengganggu) adalah menyalin dan menempelkan petak kode yang luas, atau sepotong kode sepuluh baris untuk mendapatkan beberapa data pengguna (lengkap dengan inline SQL query) disisipkan ke dalam puluhan halaman PHP atau ASP.NET. Jadi, duplikat kode dari tempat lain di proyek yang sama.

Pembaruan: Ada beberapa jawaban yang sangat bagus di sini; Saya telah menjelaskan dalam komentar mengapa saya memilih jawaban Scott Whitlock, tetapi saya juga akan sangat, sangat merekomendasikan jawaban whatsisname jika Anda berurusan dengan pelanggan yang akrab dengan manufaktur sama sekali.


Hmmm, itu yang sulit. Itu tidak diterjemahkan dengan baik ke analogi mobil / bangunan / pabrik klasik .....
whatsisname

3
Bayangkan memiliki referensi ke Partai Republik dan Demokrat dalam hukum umum AS, dan kemudian mengganti nama salah satu partai sambil menambahkan yang ketiga ... banyak hukum harus ditulis ulang.
Pekerjaan

Bagaimana dengan analogi dari: kode copy-paste (tidak aman, tidak terstruktur, dll.) Yang tidak Anda mengerti dari wiki, forum, dll. Seperti membuka lampiran email (virus, spywares, spam, dll.) Dari Pihak ketiga?
sakisk

@faif: Kode salin yang disisipkan tidak harus berupa kode sampah. Bisa jadi kode yang baik yang ditulis pria di kantor sebelah Anda. Masalah dengan kode yang disalin adalah sangat cepat menjadi mimpi buruk pemeliharaan / debugging yang tidak dapat dikelola.
whatsisname

1
@faif: lalu zap bagian tanda kurung
whatsisname

Jawaban:


36

Seperti ini ... Anda punya satu jam di rumah Anda. Besar! Anda tahu jam berapa sekarang, tetapi Anda selalu harus pergi ke satu ruangan untuk melihatnya.

Tetapi tentu saja Anda ingin tahu jam berapa sekarang tanpa pergi ke kamar itu sepanjang waktu, jadi Anda membeli beberapa jam lagi, dan Anda membagikannya di rumah Anda. Masing-masing jam ini independen. Mereka semua menjaga waktu mereka sendiri. Ini berarti:

  • Ketika waktu berubah karena waktu musim panas, Anda harus mengubah semuanya
  • Bahkan ketika mereka sudah siap, mereka semua agak berbeda dan jarang setuju dengan sempurna. Seiring waktu mereka melayang.

Sekarang bayangkan masalah yang sama di fasilitas besar dengan puluhan atau ratusan jam. Itu sebabnya Anda memerlukan sesuatu seperti jam jaringan ini yang tetap sinkron dengan basis waktu pusat. Dengan begitu waktu didefinisikan sekali dan hanya sekali .

Program copy-paste seperti membeli jam yang lebih mandiri. Itu tidak skala.


1
Saya memilih jawaban ini karena saya pikir ini bekerja paling baik untuk situasi yang biasa saya alami - sebagian besar perangkat lunak yang saya lihat adalah untuk orang-orang di sektor jasa, dan pembuatan analogi sering kali sulit untuk mereka pahami. Tetapi hampir semua orang memiliki beberapa jam di rumah mereka. Saya juga suka karena saya dapat menggunakan fakta bahwa setiap jam di rumah Anda mungkin memiliki proses yang berbeda untuk mengubah waktu (dan cepat / lambat dengan jumlah yang berbeda) sebagai cara untuk menjelaskan mengapa pencarian dan penggantian tidak merupakan opsi untuk pemeliharaan kode salin-tempel.
EZ Hart

38

Bayangkan Anda sedang merancang pesawat terbang. Anda punya jet mesin tunggal. Itu laku. Sekarang Anda akan merancang pesawat bermesin 4 untuk jarak jauh melintasi lautan.

Sekarang, Anda tidak membuat set lengkap spesifikasi teknik dan gambar untuk masing-masing mesin, bukan? Tidak, Anda menggunakan mesin yang sama di keempat tempat. Sekarang bayangkan jika Anda memiliki 4 set gambar, dan Anda harus mengubah sesuatu. Sekarang Anda harus mengubahnya di keempat gambar mesin. Apa yang terjadi jika Anda tidak sengaja lupa mengubah sesuatu di mesin ke-4 karena Anda melamun?

Jadi katakanlah Anda mengubah panjang sekrup, atau pipa threading. Sekarang Anda tidak bisa hanya "mencari dan mengganti" pada database gambar teknik Anda, Anda mungkin secara tidak sengaja mengubah sekrup pemasangan di pompa bahan bakar karena ukurannya sama. Atau jalur hidraulik yang memberi daya pada kemudi ekor menggunakan benang yang sama, tetapi sekarang ini berbeda dan Anda tidak dapat memberi daya pada ekornya lagi.

Sekarang bayangkan Anda direpotkan oleh NTSB karena mesin Anda secara acak melemparkan bilah turbin dan meledak saat terbang ke selatan Florida. Sekarang gambar mesin mana yang Anda lihat? Semuanya, salah satunya? Bagaimana Anda tahu bahwa keempatnya sama? Mungkin koreksi dibuat, tetapi mereka hanya diterapkan pada mesin satu, karena orang yang merancang mesin meninggalkan satu tahun lalu untuk bermain di band reggae dan satu-satunya yang ingat bahwa empat mesin berada di file yang terpisah, dan orang yang memperbaiki turbin yang meledak adalah penggantinya.

Menyalin dan menempelkan kode analog dengan memiliki duplikat gambar bagian-bagian komponen, apakah itu sekrup atau mesin. Anda ingin mengabstraksi komponen hingga ke bagian fundamental yang digunakan kembali sebanyak mungkin.

Jangan menduplikasi mesin, cukup tulis kode yang memasang mesin ke sayap.


11
Sekarang, bayangkan Anda menemukan mesin nomor 4 berbeda dari tiga lainnya. Apakah perbedaan ini dimaksudkan? Apakah dirancang untuk mengatasi masalah torsi tertentu yang disebabkan oleh belok kiri segera setelah lepas landas? Atau apakah itu kesalahan dalam menyalin?
David Thornley

5
Analogi yang bagus ... tetapi jika seseorang memiliki kesulitan memahami kode salin / tempel ... mesin jet mungkin sama sulitnya :)
Steven Evers

Anda harus berbicara tentang roket bahan bakar padat, bukan mesin jet untuk analogi ini. Dengan begitu, Anda bisa selesai dengan, "Lihat? Sama seperti dalam ilmu roket."
Detly

Ini bukan analogi. Cetak biru secara harfiah kode untuk artefak mekanik.
intuited

7

Anda harus menjelaskannya dalam hal berbagi sumber daya yang sama dengan menduplikasi sumber daya yang sama.

Misalnya, apakah masuk akal bagi setiap rumah di kota besar untuk memiliki pembangkit listrik khusus yang menyediakan listrik untuk rumah itu atau akankah lebih masuk akal bahwa setiap rumah berbagi pembangkit listrik yang sama? Jika terjadi kesalahan dengan komponen tertentu yang digunakan di pembangkit listrik dan perbaikan diperlukan, akan lebih mudah untuk membuat perbaikan di satu tempat dan semua orang mendapat manfaat dari perbaikan ini dibandingkan membuat perbaikan di setiap pembangkit listrik khusus dan hanya masing-masing manfaat rumah secara individual.


7

"Hei, lihat semua operasi agak mirip kan ?, jadi kamu tidak keberatan jika aku secara acak menyalin instruksi bedah untuk prosedur berbeda dari ahli bedah yang berbeda untuk operasi kamu?"


1
Besar!!! Operasi dilakukan dengan pisau kan? Biarkan saya menggunakan pisau Tukang Daging untuk melakukan operasi otak pada Anda.
Aditya P

1
@AdityaGameProgrammer: Ketika satu-satunya alat yang Anda miliki adalah pisau daging, semuanya tampak seperti ham.
Joey Adams

6

Salin dan tempel seperti mencoba membuat bagian tanpa cetakan. Ini lambat, dan Anda akan mendapatkan penggunaan satu kali dari setiap bagian, karena setelah itu ditentukan menjadi rusak atau rusak, Anda tidak bisa hanya memperbaiki cetakan untuk membuat pengganti yang cocok.

Dalam mencari analogi, pertama-tama kita harus mempertimbangkan bahaya dari program copy dan paste :

  • Bug diperkenalkan karena salinannya tidak pas (variabel yang tidak perlu dan jalur kode tidak dibersihkan)
  • Peningkatan persyaratan pengujian - abstraksi membantu menghilangkan kebutuhan untuk pengujian regresi karena Anda hanya menguji apa yang Anda ubah, dan Anda hanya mengubah daun, bukan cabang.
  • Duplikasi menduplikasi semuanya, termasuk bug. Setiap perbaikan bug, atau fitur yang berlaku untuk kedua bagian kode sekarang membutuhkan biaya dua kali lipat untuk diterapkan dan ada kemungkinan besar untuk melupakannya sepenuhnya.
  • Cari dan ganti memperburuk masalah di atas, karena Anda tidak dapat dengan mudah menemukan kode duplikat.

Senjata utama dalam perang melawan copy paste adalah abstraksi . Jadi untuk menemukan analogi yang baik, cari contoh abstraksi di dunia sekitar kita.

Abstraksi didasarkan pada ide pengaturan definisi dan kemudian melanjutkan untuk menggunakan definisi tersebut dalam eksekusi. Seperti apa dunia tanpa definisi?

  • Definisi adalah bagian utama dari bahasa hukum. Bayangkan sebuah kontrak yang tidak memiliki definisi inti tetapi sepenuhnya didefinisikan setiap istilah setiap kali digunakan.
  • Definisi dan templat digunakan dalam konstruksi. Masalah umum dalam konstruksi adalah membuat setiap potongan baru berdasarkan yang terakhir daripada pada pengukuran tunggal yang diambil di awal. Ini dapat menghasilkan panjang yang sangat bervariasi dari waktu ke waktu.
  • Organisasi perusahaan didasarkan pada abstrak dan definisi. Bagaimana jika setiap kali perusahaan Anda harus berkembang, mereka harus mendefinisikan peran baru dari awal? Itu tidak akan berhasil. Jadi bagaimana jika mereka memutuskan untuk hanya memilih peran pekerjaan yang sama dan sedikit memodifikasinya sesuai. Semua orang akan terkunci pada tempatnya karena tidak mungkin untuk memindahkan sumber daya di sekitar.

Menyalin hanya memiliki tempat ketika karya yang disalin bersifat permanen. Kalau tidak, setiap salinan membuat cabang baru untuk ditangani - diuji, dipelihara, dan ditingkatkan secara terpisah.

Abstraksi memperjuangkan ini dengan mengikat semua cabang bersama menjadi satu batang, dan mengisolasi modifikasi ke cabang yang lebih kecil atau bahkan meninggalkan.


2
Saya suka analogi cetakan, sisanya, saya khawatir, tidak akan banyak membantu pengguna non-teknologi.
Matthieu M.

@ Matthieu - Saya tidak tahu apakah Anda mengacu pada poin-poin pertama, tetapi saya tidak mengatakan itu analog, saya menggambarkan apa yang saya pikir sebagai proses pemikiran bagi pengembang untuk memikirkan analogi yang baik.
Nicole

4

Saya pikir Anda berbicara tentang kode duplikat, bukan menyalin paste (menggunakan snippet dan sejenisnya).

Berikut ini analogi dari buku sejarah, yang menggambarkannya dengan sangat baik. Sebelum pers Gutenberg para biarawan duduk dan menulis buku-buku dengan tangan dan menulis ulang buku yang sama berulang-ulang. Buku-buku yang ditulis oleh para bhikkhu, sering kali mengandung bug dan terima kasih kepada Gutenberg masalah ini telah dieliminasi.

Analogi lain: mesin uang. Anda memiliki satu mesin ATM yang dapat melayani berbagai kartu dan selalu melayani mereka dengan baik. Kode duplikat menciptakan mesin uang yang berbeda, jadi semua orang harus pergi ke mesin uang yang berbeda dan kadang-kadang mesin itu bahkan memberi Anda BSOD.

Ada artikel yang mengagumkan tentang menempelkan salinan dari Jeff http://www.codinghorror.com/blog/2009/04/a-modest-proposal-for-the-copy-and-paste-school-of-code-reuse. html

PS Saya tahu ada mesin cetak sebelum Gutenberg.


2

Bagi yang bukan programmer, saya berasumsi bahwa kita berbicara tentang orang-orang bisnis, jadi saya akan singkat dan melibatkan realitas uang.

  1. Setiap baris kode dikenakan biaya uang (baik tertulis atau disalin)
  2. Setiap bug lebih mahal dari setiap baris.
  3. Setiap baris kode menambah bug potensial
  4. Kode duplikat = duplikat bug
  5. Bug duplikat hampir tidak pernah ditemukan dalam siklus pengujian yang sama.

Potong dan tempel = Membakar Uang.


1

Tidak bisakah saya menjawab pertanyaan tetapi katakan Anda benar-benar tidak memerlukan analogi di sini, dan mencoba menemukan analogi yang tepat untuk setiap idiom atau pola pengembangan tampaknya berlawanan dan seringkali kontra produktif. Ini seperti mencoba melakukan yoga dengan kaki datar ...

Ada beberapa alasan mengapa salin / tempel menyebabkan masalah, menyebarkan bug yang ada ke area yang baru ditempelkan, di beberapa lingkungan di mana dulu dianggap sebagai peningkatan kinerja, sebenarnya sekarang lebih lambat (saya dapat memberikan contoh jika ada yang tertarik, tetapi turun ke JIT dan apakah Anda benar-benar berpikir Anda lebih pintar daripada kompiler modern?).

Ini menunjukkan pengembangnya malas atau egois atau keduanya. Jika ini adalah pertempuran yang sedang Anda lawan dalam sebuah tim saat ini, tergantung pada posisi Anda di tim ini (pimpinan tim / jnr dev, snr dev, apa pun) yang Anda perlukan untuk memperbaikinya, mungkin melalui arbitrase dalam organisasi Anda.

EDIT: Sehubungan dengan komentar di bawah ini, bahwa ini adalah kode yang meninjau kode pihak ketiga atas nama pihak ketiga (atau mungkin bahkan pihak keempat :)) Ada beberapa hal berguna yang dapat saya tambahkan semoga.

Pertama, ketika kode diproduksi untuk pihak ketiga, apakah mereka memiliki metrik? Lines of Code (LoC) misalnya.

Saya masih berpikir beberapa dari apa yang saya katakan di atas masih diperhitungkan. Mungkin seharusnya saya juga bertanya apa tujuan dari ulasan tersebut. Jika ingin mendapatkan penawaran untuk mempertahankannya, atau menggantinya, Anda harus mengajukan banyak pertanyaan berbeda.

Either way, Anda menilai kualitas kode, baik, salin setiap pasta jatuh di bawah kategori "Pengembang menunjukkan pemahaman yang memadai tentang abstraksi dan / atau desain kontrol aliran program":

Komentar: Pengembang gagal menunjukkan pemahaman tentang abstraksi, dan pendekatan mereka terhadap kontrol aliran program cenderung mengalami kesalahan. Anda dapat memperkenalkan "Kompleksitas siklus" di sini. Ini sebenarnya cukup mudah dimengerti, dan dalam putaran tentang cara saya pikir saya mungkin telah menemukan jawaban: D Yay untuk saya.

Ok, kompleksitas Cyclomatic seperti ini. Anda punya peta. Ini memiliki posisi awal Anda dan setiap tujuan yang memungkinkan. Tidak harus banyak. Pikirkan, parkir mobil, kafe, toilet. Kompleksitas siklomatik adalah ukuran jumlah rute berbeda yang ada untuk mencapai posisi awal Anda ke salah satu tujuan.

Salin dan kode yang disisipkan mungkin akan meningkatkan kompleksitas siklomatik karena itu akan mencakup logika berulang yang bisa diabstraksi ke dalam blok namanya sendiri (atau metode).

Tampak masuk akal?


Agar lebih jelas, ini adalah kode yang ditulis organisasi lain, dan sedang dibawa ke organisasi kami untuk ditinjau. Jadi ini bukan pertempuran di dalam organisasi saya, tetapi sesuatu yang saya perlu membuat orang (non-programmer) dari organisasi lain mengerti.
EZ Hart

Itu berguna untuk diketahui dan membuatnya jauh lebih mudah bagi saya untuk berguna semoga :) Saya akan menambahkan suntingan.
Ian

Maaf, sudah lama diedit, tapi saya pikir tldr adalah salin dan kode yang disisipkan adalah bau kode yang menunjukkan peningkatan kompleksitas siklomatik (antara lain) dan kompleksitas siklomatik sangat mudah dijelaskan dengan menggunakan metafora menjadi satu sisi.
Ian

1

Ambil kata bahasa Inggris untuk sesuatu. Sekarang bayangkan setiap kali Anda ingin menggambarkan hal itu, Anda menggunakan definisi kamus lengkap bukan hanya kata. Seberapa mudah bagi orang lain untuk memahami Anda?

Saya membentuk citra mental tentang sesuatu yang tidak ada atau tidak (bayangkan) itu menunjukkan tindakan atau keadaan yang tergantung pada orang lain; Masa lalu sederhana. Menunjukkan masa depan yang relatif terhadap waktu yang lalu. Mengindikasikan suatu tindakan di masa lalu yang terjadi berulang-ulang atau yang biasa (akan) tidak mudah; membutuhkan upaya fisik atau mental yang hebat untuk mencapai atau memahami atau bertahan (sulit).

Juga tidak ada salahnya untuk menunjukkan contoh nyata sebelum dan sesudah kode nyata yang telah di-refactored untuk menghapus duplikasi.


Saya sarankan berlatih paragraf kedua untuk memberikan gaya Leslie Nielsen :-)
Karl Bielefeldt

1

Ada juga masalah keamanan dan integritas kode.

Seperti diperlihatkan di sini , dimungkinkan untuk menyematkan data jahat dalam karakter unicode yang ditransfer ke clipboard.

Bergantung pada bagaimana editor Anda merespons karakter unicode, ini dapat mengakibatkan perubahan kode sumber yang tidak terduga, output kompiler yang tidak terduga atau beberapa hal yang belum saya pikirkan.


0

Ada beberapa rute berbeda yang bisa saya lihat di sini:

  1. Plagiarisme - Beberapa orang mungkin ingat ini dari sekolah di mana pencurian kekayaan intelektual adalah hal yang tidak boleh. Pemrograman copy-paste bisa seperti ini karena seseorang mungkin tidak memahami sumber atau apa yang didapat dari menggunakan solusi tertentu yang hanya disalin dan ditempelkan secara membabi buta tanpa menganalisis seberapa baik ini bekerja dan memahami mengapa ini mungkin atau tidak mungkin solusi efektif untuk masalah tersebut.

  2. Mengikuti petunjuk secara buta - Kebanyakan orang mungkin memiliki pengalaman harus pergi ke suatu tempat yang belum pernah mereka kunjungi sebelumnya. Beberapa mungkin telah menggunakan MapQuest atau Google Maps untuk menemukan tempat dan kemudian mengikuti arahan yang diberikan. Ada cerita tentang orang-orang yang tersesat atau tidak menemukan di mana mereka seharusnya berada meskipun perangkat lunak memberikan instruksi spesifik tentang bagaimana menuju ke sana. Ini adalah bahaya besar lain dari salin-rekat adalah seperti halnya seseorang memberi Anda arahan untuk pergi dari A ke B tanpa membiarkan Anda melihat peta area yang mungkin membuat perjalanan sedikit lebih sulit. Jika itu tampaknya tidak sulit, Anda bisa menaikkan taruhan dengan meminta orang tersebut pergi dari A ke B dengan menggunakan penutup mata sehingga mereka harus bergantung pada indera lain untuk menentukan arah mana yang mereka hadapi dan mencapai target.

Data, Informasi, Pengetahuan, dan Kebijaksanaan mungkin merupakan model yang baik yang dapat dirujuk untuk menunjukkan mengapa pencarian dan penggantian tidak efektif sebagai solusi karena salin dan tempel sangat mekanis dan tanpa banyak berpikir sehingga data yang ditransfer mungkin tanpa pengetahuan dan kebijaksanaan menggunakannya dengan benar. Orang bisa melihat energi nuklir untuk contoh bagaimana memahami perbedaan bisa sangat kuat. Bandingkan reaktor nuklir dengan bom nuklir dalam hal keselamatan dan penggunaan untuk melihat bagaimana mengetahui apa yang terjadi di mana tidak cukup untuk memanfaatkan kekuatan atom dengan aman.


0

Bayangkan Anda memiliki sekelompok siswa dan seperangkat aturan untuk sekolah. Alih-alih memposting aturan di tempat umum semua siswa harus referensi Anda menyerahkan masing-masing salinan aturan. Setiap siswa diberitahu bahwa mereka harus mengikuti salinan aturan mereka ke surat itu.

Sekarang modifikasi salah satu aturan yang mengatakan bahwa dalam kasus bencana Anda harus pergi ke tempat penampungan bencana yang baru. Anda harus pergi ke setiap siswa dan mengubah seperangkat aturan mereka. Jika salah satu siswa terjawab dan angin topan menghantam siswa akan pergi ke tempat lama dan mati dengan kematian yang mengerikan.


0

Seseorang mengirimi Anda email dengan templat dokumen terlampir. Jangan ragu untuk terus menggunakannya sampai template berubah. Jangan khawatir, mereka tidak akan lupa mengirimi Anda salinan yang disegarkan.


0

Model biaya CoCoMo.

http://en.wikipedia.org/wiki/COCOMO

Usaha Diterapkan (E) = a * (KLOC) ** b, di mana b> 1.0

Eksponen itu berarti upaya untuk membangun / memelihara / mendukung / menulis ulang tumbuh lebih cepat daripada jumlah baris kode.


0

Ada aspek penting lain dari praktik buruk ini yang belum ada yang dipertimbangkan: dengan menyalin secara buta (penuh atau sebagian) kode dari orang lain ( tanpa izin mereka ) Anda mungkin melanggar hukum hak cipta .


0

Pengodean salin-rekat yang saya lihat adalah tempat di mana pengembang tidak mengerti atau ingin menjelaskan apa yang mereka lakukan, dan menyalin bersama bagian-bagian berbeda yang sudah melakukan "lebih atau kurang" apa yang mereka butuhkan, secara acak mengguncang mereka pada akhirnya untuk membuat mereka cocok bersama.

Ada tiga masalah utama dengan itu:

  1. Itu tidak pernah menghasilkan kode bebas bug. Pernah.
  2. Jika mereka tidak memahami kode saat menulisnya, mereka tidak akan pernah bisa mengetahuinya saat debugging. Hanya orang lain yang dapat membersihkan kekacauan yang mereka buat, dengan biaya tambahan.
  3. Jika mereka menghindari memikirkan kode yang mereka tulis, mereka menghindari belajar. Jika mereka menghindari belajar, mereka tidak akan pernah menjadi programmer yang baik. Jika mereka tidak akan pernah menjadi programmer yang baik, mengapa mereka ada di tim Anda?

0

Katakanlah Anda memiliki 5 pacar (Anda anjing licik Anda) dan Anda ingin mengirim mereka semua pesan valentine. Anda mengetikkan huruf pertama, menambahkan namanya dan menyebutkan sesuatu yang mengesankan yang Anda bagikan bersama. Anda kemudian menyalin dan menempel surat itu empat kali, setiap kali kehilangan nama pacar # 1 dengan copy dan paste karena Anda membuat kesalahan ketik. Sekarang, 4 dari lima pacar Anda sedang menuju rumah pacar # 1.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.