Caching. Bagian 2: 60 hari sebelum rilis

Halo! Saya sudah menulis kepada Anda tentang bagaimana mempromosikan inisiatif dalam sebuah perusahaan. Lebih tepatnya, bagaimana (kadang-kadang) ini berhasil, dan kesulitan apa yang mungkin timbul: Retrospektif penggaruk. Bagaimana solusi buatan sendiri ternyata lebih keren daripada solusi berbayar dan Bagaimana kami memilih sistem caching. Bagian 1 .

Hari ini saya ingin melanjutkan dan berbicara tentang momen psikologis yang paling menegangkan dalam proyek itu, tentang mana dua artikel pertama - ketika hasil dari proyek ditentukan bukan oleh keterampilan teknis tim, melainkan kepercayaan pada perhitungan dan kemauan mereka untuk mencapai tujuan.

Saya harus mengatakan - saya pikir untuk membawa proyek ke momen yang intens - itu adalah kesalahan yang jauh digunakan tentang lshaya daripada heroisme dengan merentangkan proyek dari masalah ini ....
Tapi, saya tidak menyembunyikan pengalaman ini dan rela membagikannya - karena saya mempertimbangkan:

  • tepatnya area bermasalah adalah titik pertumbuhan
  • masalah terbesar "tiba" tepatnya dari tempat yang tidak Anda harapkan

Kombinasi dari poin-poin ini - hanya mengharuskan Anda untuk berbagi pengalaman indah tentang "cara mendapatkan selokan tiba-tiba." Tapi, perlu dicatat, situasi yang serupa luar biasa di perusahaan Sportmaster. Artinya, ada kemungkinan bahwa situasi ini akan terjadi lagi - perencanaan dan definisi tanggung jawab sekarang - pada tingkat yang sama sekali berbeda.

Jadi, sepertinya perkenalan sudah cukup, jika Anda siap - selamat datang di kucing.



Juni 2017 Kami memodifikasi panel admin. Panel admin tidak hanya seperangkat formulir dan tabel di antarmuka web - nilai yang dimasukkan harus direkatkan dengan puluhan data lain yang kami dapatkan dari sistem pihak ketiga. Plus, entah bagaimana mengubah dan, akhirnya, mengirimkannya kepada konsumen (yang utamanya adalah situs ElasticSearch Sportmaster).

Kesulitan utama hanya untuk mengkonversi dan mengirim. Yaitu:

  1. Anda perlu menyediakan data dalam bentuk json, yang masing-masing berbobot 100Kb, dan beberapa muncul hingga 10MB (memindai ketersediaan dan kriteria pengiriman barang ke toko)
  2. ada json dengan struktur yang memiliki lampiran rekursif dari setiap tingkat sarang (misalnya, menu di dalam item menu, di mana ada item menu lagi, dll.)
  3. pernyataan akhir tidak disetujui dan terus berubah (misalnya, bekerja dengan barang oleh Model digantikan oleh pendekatan ketika kami bekerja dengan Model Warna). Secara konstan - ini beberapa kali seminggu, dengan tingkat puncak 2 kali sehari selama seminggu.

Jika 2 poin pertama adalah murni teknis, dan ditentukan oleh tugas itu sendiri, maka dengan poin ke-3, tentu saja, Anda harus menghadapinya secara organisasi. Tapi, dunia nyata jauh dari ideal, jadi kami bekerja dengan apa yang kami miliki.

Yaitu, mereka menemukan cara cepat memusatkan formulir web dan objek mereka di sisi server.

Satu orang dari tim ditunjuk untuk peran "tamparan formulir" profesional dan, menggunakan komponen web yang disiapkan, meluncurkan demo untuk ui lebih cepat daripada analis mengoreksi gambar ui ini.

Tetapi untuk mengubah skema transformasi, kompleksitas muncul di sini.

Pertama, kami pergi dengan cara biasa - untuk melakukan transformasi dalam sql-query ke Oracle. Ada spesialis DB di tim. Itu berlangsung sampai saat ketika permintaan adalah 2 halaman teks sql kontinu. Saya bisa terus dan terus, tetapi ketika perubahan datang dari analis - secara objektif, hal yang paling sulit adalah menemukan tempat di mana membuat perubahan.

Analis menyatakan aturan dalam skema, yang, meskipun mereka dicat dalam sesuatu yang terlepas dari kode (sesuatu dari visio / draw.io / gliffy), tetapi ada begitumirip dengan kotak dan panah di sistem ETL (misalnya, Pentaho Kettle, yang pada waktu itu digunakan untuk memasok data ke situs web Sportmaster). Sekarang, jika kita tidak memiliki query SQL, tetapi skema ETL! Kemudian pernyataan dan solusinya akan dinyatakan secara topologis identik, yang berarti bahwa mengedit kode dapat memakan waktu sebanyak mengedit pernyataan!

Tetapi dengan sistem ETL ada kesulitan lain. Ketel Pentaho yang sama - sangat bagus ketika Anda perlu membuat indeks baru di ElasticSearch, di mana untuk menulis semua data yang dilem dari beberapa sumber (komentar: sebenarnya, Ketel Pentaho yang tidak berfungsi dengan baik, karena tidak menggunakan javascript dalam transformasi terkait dengan kelas java di mana konsumen mengakses data - karena ini, Anda dapat menulis sesuatu yang Anda tidak dapat berubah menjadi objek pojo yang diperlukan nanti, tetapi ini adalah topik yang terpisah, jauh dari jalan utama artikel).

Tetapi apa yang harus dilakukan ketika di panel admin pengguna mengoreksi satu bidang dalam satu dokumen? Untuk mengirimkan perubahan ini ke situs web ElasticSearch Sportmaster, jangan buat indeks baru untuk mengisi semua dokumen jenis ini, termasuk yang diperbarui!

Saya ingin bahwa ketika satu objek dalam data input berubah, maka kirim pembaruan ke ElasticSearch situs hanya untuk dokumen output yang sesuai.

Oke, dokumen masukan itu sendiri, tapi bagaimanapun, sesuai dengan skema transformasi, itu bisa dilampirkan ke dokumen dari jenis yang berbeda melalui bergabung! Jadi, Anda perlu menganalisis skema transformasi dan menghitung dokumen keluaran mana yang akan dipengaruhi oleh perubahan data di sumber.

Pencarian produk kotak untuk mengatasi masalah ini tidak mengarah pada apa pun. Tidak ditemukan.
Dan ketika mereka putus asa untuk menemukan, mereka menemukan jawabannya, tetapi bagaimana cara kerjanya di dalam, dan bagaimana ini bisa dilakukan?

Gagasan muncul segera.

Jika ETL akhir dapat dipecah menjadi bagian-bagian penyusunnya, yang masing-masing memiliki tipe tertentu dari himpunan terbatas (misalnya, filter, gabung, dll.), Maka dimungkinkan untuk membuat himpunan node khusus yang terbatas yang sama yang sesuai dengan yang asli, tetapi dengan perbedaan bahwa mereka bekerja bukan dengan data itu sendiri, tetapi dengan perubahan mereka?

Secara terperinci, dengan contoh dan poin utama dalam implementasi, solusi kami - saya ingin membahas dalam artikel terpisah. Untuk menghadapi posisi pendukung - ini akan membutuhkan perendaman serius, kemampuan untuk berpikir secara abstrak dan mengandalkan apa yang belum terwujud. Memang, itu akan menarik justru dari sudut pandang matematika dan menarik hanya untuk orang-orang Habrovit yang tertarik pada detail teknis .
Di sini saya hanya bisa mengatakan bahwa kami membuat model matematika di mana kami menggambarkan 7 jenis node dan menunjukkan bahwa sistem ini lengkap - yaitu, menggunakan 7 jenis node dan koneksi di antara mereka - skema transformasi data apa pun dapat diekspresikan. Implementasinya didasarkan pada penggunaan aktif untuk memperoleh dan merekam data dengan kunci (yaitu dengan kunci, tanpa syarat tambahan).

Dengan demikian, solusi kami memiliki titik kuat mengenai semua kesulitan pengantar:

  1. data harus diberikan dalam bentuk json -> kita bekerja dengan objek pojo (objek java lama polos, jika seseorang tidak menemukan waktu ketika penunjukan tersebut digunakan), yang mudah untuk menyalip di json
  2. ada json dengan struktur yang memiliki embeddings rekursif dari setiap tingkat sarang -> lagi, pojo (hal utama adalah bahwa tidak ada loop, tetapi berapa banyak tingkat sarang tidak penting, mudah untuk memproses di Jawa melalui rekursi)
  3. pernyataan terakhir terus berubah -> sangat baik, karena kami mengubah skema transformasi lebih cepat daripada keinginan analis (dalam diagram) untuk eksperimen

Dari saat-saat berisiko, hanya satu - kita menulis solusinya dari awal, atas keinginan kita sendiri.

Sebenarnya, jebakan itu tidak lama datang.

Momen spesial N1. Perangkap. “Diperkirakan dengan baik”


Kejutan lain yang bersifat organisasional adalah bahwa pada saat yang sama dengan perkembangan kami, repositori master utama pindah ke versi baru, dan format di mana repositori ini menyediakan data berubah. Dan alangkah baiknya jika sistem kami segera bekerja dengan penyimpanan baru, dan tidak dengan yang lama. Tetapi penyimpanan baru belum siap. Tapi kemudian, struktur data diketahui dan mereka bisa memberi kita demo di mana sejumlah kecil data terkait akan dituangkan. Pergi?

Di sini, di dalam pendekatan produk, ketika bekerja dengan aliran pasokan nilai, sebuah peringatan secara tegas dipalu ke semua optimis: ada pemblokir -> tugas tidak bekerja, titik.

Tapi kemudian, ketergantungan seperti itu bahkan tidak menimbulkan kecurigaan. Memang, kami gembira dari kesuksesan dengan prosesor Delta prototipe - sistem untuk memproses data delta (implementasi model matematika ketika perubahan dalam data output dihitung menggunakan skema transformasi sebagai respons terhadap perubahan dalam input data).

Di antara semua skema transformasi, satu adalah yang paling penting. Selain fakta bahwa sirkuit itu sendiri adalah yang terbesar dan paling kompleks, ada juga persyaratan ketat untuk transformasi yang harus dilakukan sesuai dengan sirkuit ini - batas waktu pada pelaksanaan jumlah penuh data.

Jadi, transformasi harus dilakukan 15 menit dan tidak lebih lama. Input utama adalah tabel dengan 5,5 juta catatan. Pada tahap pengembangan, tabel belum diisi. Lebih tepatnya, itu diisi dengan data uji kecil yang ditetapkan dalam jumlah 10 ribu baris.

Baiklah, mari kita mulai. Dalam implementasi pertama, prosesor Delta bekerja pada HashMap sebagai penyimpanan Nilai-Kunci (izinkan saya mengingatkan Anda, kami perlu membaca dan menulis banyak objek dengan kunci). Tentu saja, bahwa pada volume produksi, semua objek perantara tidak akan muat di memori - karena itu, alih-alih HashMap, kami beralih ke Hazelcast.

Mengapa persis Hazelcast - jadi karena produk ini sudah dikenal, digunakan di backend ke situs Sportmaster. Plus, ini adalah sistem terdistribusi dan, seperti yang terlihat bagi kami - jika seorang teman melakukan sesuatu yang salah dengan kinerja - kami menambahkan lebih banyak contoh ke beberapa mesin dan masalah terselesaikan. Dalam kasus ekstrim - selusin mobil. Penskalaan horisontal dan semua hal.

Jadi, kami meluncurkan prosesor Delta kami untuk transformasi yang ditargetkan. Ini bekerja hampir secara instan. Ini bisa dimengerti - datanya hanya 10 ribu bukannya 5,5 juta. Oleh karena itu, kami mengalikan waktu yang diukur dengan 550, dan kami mendapatkan hasilnya: sekitar 2 menit. Baik! Bahkan - kemenangan!

Ini adalah awal dari pekerjaan proyek - tepat ketika Anda perlu memutuskan arsitektur, mengkonfirmasi hipotesis (melakukan tes yang mengkonfirmasi mereka), mengintegrasikan solusi pilot secara vertikal.

Karena tes menunjukkan hasil yang sangat baik - yaitu, kami mengkonfirmasi semua hipotesis, kami dengan cepat membalikkan pilot - menyatukan "kerangka" yang terintegrasi secara vertikal untuk sebagian kecil fungsi. Dan mereka memulai pengkodean utama - mengisi "kerangka dengan daging."

Apa yang berhasil dan bersemangat terlibat. Hingga hari yang indah itu, ketika satu set data lengkap diunggah ke toko induk .

Jalankan tes pada set ini.

Setelah 2 menit tidak berhasil. Saya juga tidak bekerja setelah 5, 10, 15 menit. Artinya, mereka tidak cocok dengan kerangka kerja yang diperlukan. Tetapi, dengan siapa hal itu tidak terjadi, akan perlu untuk men-tweak sesuatu secara detail dan bugar.

Tetapi tes tidak bekerja satu jam kemudian. Dan bahkan setelah 2 jam ada harapan bahwa dia akan bekerja, dan kami akan mencari apa yang diperketat. Sisa-sisa harapan bahkan setelah 5 jam. Tapi, setelah 10 jam, ketika mereka pulang, tetapi tes masih tidak berhasil - tidak ada harapan lagi.

Masalahnya adalah bahwa pada hari berikutnya, ketika mereka datang ke kantor, tes masih rajin bekerja. Akibatnya, itu bergulir selama 30 jam, tidak menunggu, dimatikan.
Malapetaka!

Masalahnya terlokalisasi dengan cukup cepat.

Hazelcast - ketika mengerjakan sejumlah kecil data - sebenarnya menggulirkan semua yang ada dalam memori. Tetapi ketika diminta untuk membuang data pada disk - kinerja dicelupkan ribuan kali.

Pemrograman akan menjadi pekerjaan yang membosankan dan hambar, jika bukan karena pihak berwenang dan kewajiban untuk memberikan produk jadi. Jadi kami, secara harfiah sehari kemudian, setelah kami menerima set data lengkap - kita perlu pergi ke pihak berwenang dengan laporan tentang bagaimana tes pada volume produksi berlalu.

Ini adalah pilihan yang sangat serius dan sulit:

  1. katakan “apa adanya” = tinggalkan proyek
  2. katakan "sesuka saya" = untuk mengambil risiko, mungkin, tidak diketahui apakah kami dapat memperbaiki masalahnya

Untuk memahami perasaan apa yang muncul dalam kasus ini, hanya mungkin untuk sepenuhnya berinvestasi dalam ide, untuk merealisasikan rencana selama setengah tahun, untuk menciptakan produk yang akan membantu rekan kerja memecahkan lapisan besar masalah.

Jadi, menyerahkan ciptaan Anda yang tercinta sangat sulit.
Ini adalah karakteristik semua orang - kami menyukai apa yang telah kami lakukan dengan banyak upaya. Oleh karena itu, sulit untuk mendengar kritik - Anda harus secara sadar melakukan upaya untuk menerima umpan balik secara memadai.

Secara umum, kami memutuskan bahwa masih ada sangat, sangat banyak sistem berbeda yang dapat digunakan sebagai penyimpanan Nilai-Kunci, dan jika Hazelcast tidak cocok, maka sesuatu pasti akan berfungsi. Artinya, mereka memutuskan untuk mengambil risiko. Untuk pembenaran kita, kita dapat mengatakan bahwa itu belum "tenggat waktu berdarah" - secara umum, masih ada sedikit waktu untuk "pindah" ke solusi cadangan.

Pada pertemuan dengan bos-bos itu, manajer kami mengindikasikan bahwa "tes menunjukkan bahwa sistem bekerja dengan stabil pada volume produksi, tidak rusak". Memang, sistem bekerja dengan stabil. 60 hari

untuk rilis .

Momen spesial N2. Bukan jebakan, tapi bukan penemuan. "Kurang itu lebih"


Untuk menemukan pengganti Hazelcast dengan peran data warehouse Key-Value, kami menyusun daftar semua kandidat - kami mendapat daftar 31 produk. Ini semua yang saya berhasil google dan cari tahu dari teman-teman saya. Selanjutnya, Google memberikan beberapa opsi yang benar-benar cabul, seperti makalah siswa.

Untuk menguji kandidat lebih cepat, kami menyiapkan tes kecil yang, dalam beberapa menit peluncuran, menunjukkan kinerja pada volume yang tepat. Dan mereka memparalelkan pekerjaan - semua orang mengambil sistem berikutnya dari daftar, mengonfigurasi, menjalankan tes, mengambil yang berikutnya.
Mereka bekerja dengan cepat, mematikan beberapa sistem sehari.

Pada sistem ke-18, menjadi jelas bahwa ini tidak ada gunanya. Di bawah profil beban kami - tidak ada sistem ini yang dipertajam. Mereka memiliki banyak kerutan dan garis untuk membuatnya nyaman digunakan, banyak pendekatan indah untuk penskalaan horizontal - tetapi ini tidak memberi kita keuntungan apa pun.

Kami membutuhkan sistem yang _fast_ menyimpan kunci ke objek pada disk dan membaca kunci dengan cepat.

Jika demikian, kami menguraikan algoritme tentang bagaimana ini dapat diterapkan. Secara umum, tampaknya cukup layak - jika pada saat yang sama: a) mengorbankan jumlah data yang akan menempati disk, b) memiliki perkiraan jumlah dan ukuran karakteristik data di setiap tabel.
Sesuatu yang bergaya, mengalokasikan memori (pada disk) untuk objek dengan margin, potongan volume maksimum tetap. Kemudian gunakan tabel indeks ... dan seterusnya ...
Beruntung tidak sampai seperti ini.

Keselamatan datang dalam bentuk RocksDB.
Ini adalah produk dari Facebook yang dirancang untuk membaca cepat dan menyimpan berbagai byte ke disk. Pada saat yang sama, akses ke file disediakan melalui antarmuka yang mirip dengan penyimpanan Key-Value. Faktanya, kuncinya adalah array byte, nilainya array array byte. Dioptimalkan untuk melakukan pekerjaan ini dengan cepat dan andal. Semua. Jika Anda membutuhkan sesuatu yang lebih indah dan tingkat tinggi - mainkan sendiri.
Apa yang kita butuhkan!

RocksDB, melesat dalam peran penyimpanan Key-Value - membawa indikator uji target ke level 5 jam. Itu jauh dari 15 menit, tetapi hal utama dilakukan. Hal utama adalah memahami apa yang terjadi, untuk memahami bahwa menulis ke disk secepat mungkin, lebih cepat daripada tidak mungkin. Pada SSD, dalam pengujian yang disempurnakan, RocksDB memeras 400Mb / s, dan itu sudah cukup untuk tugas kami. Penundaan - di suatu tempat di kita, dalam kode yang mengikat.

Dalam kode kita , yang berarti kita bisa mengatasinya. Mari kita pisahkan, tapi kita bisa mengatasinya.

Momen spesial N3. Dukung. "Perhitungan teoretis"


Kami memiliki algoritma dan input. Kami mengambil rentang input data, menghitung berapa banyak tindakan yang harus dilakukan sistem, bagaimana tindakan ini dinyatakan dalam biaya run-time JVM (menetapkan nilai ke variabel, memasukkan metode, membuat objek, menyalin array byte, dll.), Ditambah berapa banyak panggilan ke RocksDB harus diadakan.

Menurut perhitungan, ternyata mereka harus bertemu 2 menit (kira-kira, seperti yang ditunjukkan tes untuk HashMap di awal, tapi ini hanya kebetulan - algoritme telah berubah sejak saat itu).

Namun, tes berjalan selama 5 jam.

Dan sekarang, sebelum rilis 30 hari.

Ini adalah tanggal khusus - sekarang tidak mungkin untuk runtuh - kita tidak akan punya waktu untuk beralih ke opsi cadangan.
Tentu saja, pada hari ini manajer proyek dipanggil ke pihak berwenang. Pertanyaannya sama - punya waktu, apakah semuanya baik-baik saja?



Berikut adalah cara terbaik untuk menggambarkan situasi ini - gambar sampul diperpanjang untuk artikel ini. Artinya, bos diperlihatkan bagian gambar yang diberikan dalam judul. Namun dalam kenyataannya - seperti itu.

Meskipun, pada kenyataannya, tentu saja - kami sama sekali tidak lucu. Dan katakan bahwa "Semuanya keren!" - ini hanya mungkin bagi seseorang dengan keterampilan penguasaan diri yang sangat kuat.
Hormat, sangat besar untuk manajer, untuk percaya, percaya pengembang.

Sungguh, kode benar-benar tersedia - menunjukkan 5 jam. Perhitungan teoritis - menunjukkan 2 menit. Bagaimana ini bisa dipercaya?

Tapi itu mungkin jika: model dirumuskan dengan jelas, bagaimana cara menghitung dapat dipahami, dan nilai apa yang harus diganti juga bisa dimengerti. Artinya, kenyataan bahwa dalam kenyataannya eksekusi membutuhkan lebih banyak waktu berarti bahwa dalam kenyataannya bukan kode yang kita harapkan untuk dieksekusi di sana yang dieksekusi.

Tugas utama adalah menemukan "pemberat" dalam kode. Artinya, beberapa tindakan dilakukan selain aliran utama pembuatan data akhir.

Terburu-buru. Tes unit, komposisi fungsional, fragmentasi fungsi dan lokalisasi tempat dengan jumlah waktu yang tidak proporsional yang dihabiskan untuk pelaksanaan. Banyak hal telah dilakukan.
Sepanjang jalan, kami merumuskan tempat-tempat di mana Anda dapat mengencangkannya dengan serius.

Misalnya, serialisasi. Pertama kali menggunakan java.io. standar Tetapi jika kita mempercepat Cryo, maka dalam kasus kita, kita mendapatkan peningkatan 2,5 kali lipat dalam kecepatan serialisasi dan pengurangan 3 kali lipat dalam volume data serial (yang berarti IO 3 kali lebih kecil, yang hanya memakan sumber daya utama). Tetapi, secara lebih rinci, ini adalah topik untuk artikel teknis yang terpisah.

Tetapi poin kuncinya, atau "tempat gajah bersembunyi" - saya akan coba uraikan dalam satu paragraf.

Poin khusus 4. Penerimaan untuk menemukan solusi. “Masalah = Solusi”


Ketika kita mendapatkan / mengatur dengan kunci - dalam perhitungan itu berjalan sebagai 1 operasi, mempengaruhi IO dalam volume yang sama dengan kunci + nilai objek (dalam bentuk serial, tentu saja).
Tetapi bagaimana jika objek itu sendiri yang kita panggil get / set adalah Map, yang juga kita dapatkan dengan get / set dari disk. Berapa banyak IO akan dilakukan dalam kasus ini?

Dalam perhitungan kami, fitur ini tidak diperhitungkan. Artinya, itu dianggap sebagai 1 IO untuk kunci + objek-nilai. Tetapi faktanya?

Misalnya, dalam penyimpanan Nilai-Kunci, dengan kunci-1 ada objek obj-1 dengan tipe Map, di mana objek obj-2 tertentu harus disimpan di bawah kunci key-2. Di sini kami berpikir bahwa operasi akan membutuhkan IO untuk key-2 + obj-2. Namun pada kenyataannya, Anda perlu mempertimbangkan obj-1, memanipulasinya dan mengirimkannya ke IO: key-1 + obj-1. Dan jika itu adalah Peta di mana ada 1000 objek, maka konsumsi IO akan menjadi sekitar 1000 kali lebih banyak. Dan jika 10.000 objek, maka ... Begitulah cara mereka mendapatkan "pemberat".

Ketika masalah diidentifikasi, solusinya biasanya jelas.

Dalam kasus kami, ini telah menjadi struktur khusus untuk manipulasi di dalam Peta bersarang. Yaitu, Nilai-Kunci seperti itu, yang untuk mendapatkan / mengatur mengambil dua kunci sekaligus, yang harus diterapkan secara berurutan: kunci-1, kunci-2 - yaitu, untuk tingkat pertama dan untuk yang bersarang. Bagaimana menerapkan struktur seperti itu - saya akan memberi tahu Anda secara detail dengan senang hati, tetapi sekali lagi, dalam artikel teknis yang terpisah.
Di sini, dari episode ini, saya menekankan dan mempromosikan fitur seperti itu: masalah yang sangat terperinci adalah solusi yang baik.

Penyelesaian


Dalam artikel ini, saya mencoba menunjukkan poin dan jebakan organisasi yang mungkin muncul. Perangkap seperti itu sangat jelas terlihat "dari samping" atau seiring waktu, tetapi sangat mudah untuk masuk ke dalamnya ketika Anda pertama kali menemukan diri Anda di sebelahnya. Saya harap seseorang akan mengingat deskripsi seperti itu, dan pada saat yang tepat pengingat akan bekerja, "Saya pernah mendengar sesuatu seperti itu di suatu tempat sebelumnya."

Dan, yang paling penting - sekarang semuanya diceritakan tentang prosesnya, tentang momen psikologis, tentang momen organisasi. Sekarang kami memiliki gagasan tentang tugas apa dan dalam kondisi apa sistem dibuat. Sekarang - Anda dapat dan harus memberi tahu tentang sistem dari sisi teknis - model matematika seperti apa ini, dan trik apa dalam kode yang kami gunakan, dan solusi inovatif apa yang kami pikirkan.

Tentang ini di artikel selanjutnya.

Sementara itu, Selamat Kode Baru!

All Articles