Untuk pertanyaan dengan gaya "mengapa?" Ada artikel yang lebih tua - Natural Geektimes - membuat ruang lebih bersih .
Banyak artikel, karena alasan subyektif, beberapa tidak suka, dan beberapa sebaliknya, sayang untuk dilewatkan. Saya ingin mengoptimalkan proses ini dan menghemat waktu.
Artikel di atas mengusulkan pendekatan dengan skrip di browser, tetapi saya tidak benar-benar menyukainya (walaupun saya pernah menggunakannya sebelumnya) karena alasan berikut:
- Untuk peramban lain di komputer / ponsel Anda, Anda harus mengonfigurasinya lagi, jika memungkinkan.
- Penyaringan keras oleh penulis tidak selalu nyaman.
- Masalah dengan penulis yang artikelnya tidak ingin dilewatkan, bahkan jika mereka diterbitkan setahun sekali, tidak diselesaikan.
Memfilter berdasarkan peringkat artikel yang dibangun di situs tidak selalu nyaman, karena artikel yang sangat khusus, untuk semua nilainya, dapat menerima peringkat yang agak sederhana.
Awalnya, saya ingin menghasilkan rss feed (atau bahkan beberapa), hanya menyisakan yang menarik di sana. Tetapi pada akhirnya ternyata membaca rss sepertinya tidak terlalu nyaman: dalam hal apa pun, untuk mengomentari / memilih artikel / menambahkannya ke favorit, Anda harus membuka peramban. Karena itu, saya menulis bot untuk telegram yang melemparkan artikel menarik kepada saya di PM. Telegram sendiri menjadikannya pratinjau yang indah, yang dikombinasikan dengan informasi tentang penulis / peringkat / tampilan terlihat cukup informatif.

Di bawah potongan, detail seperti fitur kerja, proses penulisan, dan solusi teknis.
Secara singkat tentang bot
Repositori: https://github.com/Kright/habrahabr_reader
Bot Telegram: https://t.me/HabraFilterBot
Pengguna menetapkan peringkat tambahan untuk tag dan penulis. Setelah itu, filter diterapkan ke artikel - peringkat artikel di Habré, peringkat pengguna penulis dan rata-rata untuk peringkat pengguna dengan tag ditambahkan. Jika jumlahnya lebih besar dari nilai ambang batas yang ditentukan pengguna, maka artikel melewati filter.
Tujuan sampingan menulis bot adalah untuk mendapatkan kesenangan dan pengalaman. Selain itu, saya secara teratur mengingatkan diri sendiri bahwa saya bukan Google , dan karena itu banyak hal dilakukan sesederhana dan se primitif mungkin. Namun, ini tidak mencegah proses penulisan bot dari peregangan selama tiga bulan.
Di luar jendela adalah musim panas
Juli berakhir, dan saya memutuskan untuk menulis bot. Dan tidak sendirian, tetapi dengan seorang teman yang menguasai scala dan ingin menulis sesuatu di atasnya. Awalnya tampak menjanjikan - kode akan digergaji "tim", tugas itu tampak mudah dan saya berpikir bahwa dalam beberapa minggu atau sebulan bot akan siap.
Terlepas dari kenyataan bahwa saya sendiri telah menulis kode di atas batu selama beberapa tahun terakhir, biasanya tidak ada yang melihat atau melihat kode ini: proyek kesayangan, memeriksa beberapa ide, preprocessing data, menguasai beberapa konsep dari FP. Saya benar-benar tertarik dengan bagaimana kode dalam tim terlihat, karena kode di atas batu dapat ditulis dengan cara yang sangat berbeda.
Apa yang bisa terjadi begitu ? Namun, kami tidak akan terburu-buru.
Segala sesuatu yang terjadi dapat dilacak oleh riwayat komitmen.
Seorang teman membuat repositori pada 27 Juli, tetapi tidak melakukan apa-apa lagi, jadi saya mulai menulis kode.
30 Juli
Secara singkat: Saya menulis parsing rss feed Habr.
com.github.pureconfig
untuk membaca file com.github.pureconfig
typesafe secara langsung dalam kelas kasus (ternyata sangat nyaman)scala-xml
untuk membaca xml: karena saya awalnya ingin menulis implementasi saya untuk rss tape dan rss tape dalam format xml, saya menggunakan pustaka ini untuk parsing. Sebenarnya, parsing rss juga muncul.scalatest
untuk tes. Bahkan untuk proyek-proyek kecil, menulis tes menghemat waktu - misalnya, ketika men-debug parsing xml, jauh lebih mudah untuk mengunduhnya ke file, menulis tes, dan memperbaiki kesalahan. Ketika bug kemudian muncul dengan parsing beberapa html aneh dengan karakter utf-8 yang tidak valid, ternyata lebih nyaman untuk memasukkannya ke dalam file dan menambahkan tes.- aktor dari Akka. Secara obyektif, mereka tidak diperlukan sama sekali, tetapi proyek ini ditulis untuk bersenang-senang, saya ingin mencobanya. Sebagai hasilnya, saya siap untuk mengatakan bahwa saya menyukainya. Seseorang dapat melihat gagasan OOP dari sisi lain - ada aktor yang bertukar pesan. Yang lebih menarik - Anda dapat (dan harus) menulis kode dengan harapan bahwa pesan tersebut mungkin tidak mencapai atau tidak diproses (secara umum, ketika akun dijalankan pada satu komputer, pesan tidak boleh hilang). Pada awalnya saya memeras otak saya dan ada sampah di kode dengan aktor berlangganan satu sama lain, tetapi pada akhirnya saya berhasil menghasilkan arsitektur yang agak sederhana dan elegan. Kode di dalam masing-masing aktor dapat dianggap sebagai single-threaded, ketika aktor crash, Akka me-restart itu - sistem yang agak toleran terhadap kesalahan diperoleh.
9 Agustus
Saya menambahkan proyek scala-scrapper
untuk mem-parsing halaman html dari Habr (untuk menarik informasi seperti peringkat artikel, jumlah bookmark, dll.).
Dan kucing. Mereka yang ada di batu.

Saya kemudian membaca satu buku tentang database terdistribusi, saya menyukai gagasan CRDT (tipe data direplikasi bebas konflik, https://en.wikipedia.org/wiki/Conflict-free_replicated_data_type , habr ), jadi saya memfilmkan jenis kelas dari semigroup komutatif untuk informasi tentang artikel tentang Habré.
Sebenarnya, idenya sangat sederhana - kami memiliki penghitung yang berubah secara monoton. Jumlah promotor tumbuh dengan lancar, jumlah plus juga (namun, juga jumlah minus). Jika saya memiliki dua versi informasi tentang sebuah artikel, maka Anda dapat "menggabungkannya menjadi satu" - pertimbangkan kondisi penghitung yang lebih relevan.
Semigroup berarti bahwa dua objek dengan informasi tentang suatu artikel dapat digabung menjadi satu. Komutatif berarti Anda dapat menggabungkan A + B dan B + A, hasilnya tidak bergantung pada urutan, sebagai akibatnya, versi terbaru tetap ada. Omong-omong, asosiatif juga ada di sini.
Misalnya, dengan desain, rss setelah penguraian memberikan informasi yang sedikit dibasahi tentang artikel - tanpa metrik seperti jumlah tampilan. Seorang aktor khusus kemudian mengambil informasi tentang artikel dan berlari ke halaman html untuk memperbaruinya dan bergabung dengan versi yang lama.
Secara umum, seperti akka, tidak perlu untuk ini, mungkin saja untuk menyimpan updateDate untuk artikel dan mengambil yang lebih baru tanpa merger, tetapi jalan petualangan membawaku.
12 Agustus
Saya mulai merasa lebih bebas dan, demi kepentingan, membuat setiap obrolan menjadi aktor yang terpisah. Secara teoritis, seorang aktor dengan sendirinya berbobot sekitar 300 byte dan dapat dibuat setidaknya oleh jutaan, jadi ini adalah pendekatan yang sepenuhnya normal. Ternyata, menurut saya, solusi yang agak menarik:
Satu aktor adalah jembatan antara server telegram dan sistem pesan di Akka. Dia hanya menerima pesan dan mengirimnya ke aktor obrolan yang diinginkan. Aktor-obrolan sebagai respons dapat mengirim sesuatu kembali - dan itu dikirim kembali ke telegram. Apa yang sangat nyaman - aktor ini ternyata sesederhana mungkin dan hanya mengandung logika respons terhadap pesan. Ngomong-ngomong, informasi tentang artikel baru datang ke setiap obrolan, tapi sekali lagi saya tidak melihat masalah dalam hal ini.
Secara umum, bot sudah berfungsi, merespons pesan, menyimpan daftar artikel yang dikirim ke pengguna, dan saya sudah berpikir bahwa bot sudah hampir siap. Saya perlahan-lahan menyelesaikan chip kecil seperti menormalkan nama-nama penulis dan tag (mengganti "sd f" dengan "s_d_f").
Hanya ada satu yang kecil tapi - negara tidak bertahan di mana pun.
Semuanya salah
Anda mungkin memperhatikan bahwa saya menulis bot sebagian besar sendirian. Jadi, peserta kedua bergabung dalam pengembangan, dan perubahan berikut muncul dalam kode:
- Untuk menyimpan negara muncul mongoDB. Pada saat yang sama, log pecah dalam proyek, karena untuk beberapa alasan monga mulai melakukan spamming dan beberapa orang hanya mematikannya secara global.
- Aktor-jembatan dalam telegram ditransformasikan melampaui pengakuan dan mulai mengurai pesan itu sendiri.
- Aktor untuk obrolan mabuk tanpa ampun, bukannya mereka muncul aktor yang menyembunyikan dalam dirinya semua informasi tentang semua obrolan sekaligus. Untuk setiap bersin aktor ini naik ke mongu. Ya, sulit untuk mengirimnya ke semua aktor obrolan ketika memperbarui informasi tentang suatu artikel (seperti Google, jutaan pengguna menunggu jutaan artikel dalam obrolan untuk semua orang), tetapi itu normal untuk masuk ke monga setiap kali Anda memperbarui obrolan. Seperti yang saya pahami kemudian, logika kerja dari obrolan juga sepenuhnya terpotong dan sesuatu yang tidak bekerja muncul.
- Tidak ada jejak yang tersisa dari kelas.
- Logika yang tidak sehat muncul di aktor dengan saling berlangganan, yang mengarah ke kondisi balapan.
- Struktur data dengan bidang tipe
Option[Int]
berubah menjadi Int dengan nilai default ajaib tipe -1. Kemudian saya menyadari bahwa mongoDB menyimpan json dan tidak ada yang salah dengan menyimpan Option
sana, atau setidaknya parse -1 seperti Tidak ada, tetapi pada saat itu saya tidak tahu ini dan percaya pada kata bahwa "itu perlu." Kode itu tidak ditulis oleh saya, dan saya tidak repot-repot mengubahnya untuk sementara waktu. - Saya menemukan bahwa alamat IP publik saya memiliki properti perubahan, dan setiap kali saya harus menambahkannya ke mongue daftar putih. Saya memulai bot secara lokal, monga ada di suatu tempat di server monga sebagai sebuah perusahaan.
- Tiba-tiba, normalisasi tag dan format pesan untuk telegram menghilang. (Hmm, kenapa begitu?)
- Saya suka bahwa keadaan bot disimpan dalam database eksternal, dan setelah restart, itu terus berfungsi seolah-olah tidak ada yang terjadi. Namun, ini adalah satu-satunya nilai tambah.
Orang kedua tidak terburu-buru, dan semua perubahan ini muncul dalam satu tumpukan besar di awal September. Saya tidak segera menghargai skala kerusakan dan mulai memahami pekerjaan database, karena belum pernah berurusan dengan mereka sebelumnya. Hanya kemudian saya menyadari betapa banyak kode kerja yang dipotong dan berapa banyak bug yang ditambahkan sebagai imbalan.
September
Pada awalnya, saya pikir akan berguna untuk menguasai Mongu dan melakukan semuanya dengan baik. Lalu perlahan-lahan saya mulai mengerti bahwa mengatur komunikasi dengan basis data juga merupakan seni di mana Anda dapat membuat balapan dan hanya melakukan kesalahan. Sebagai contoh, jika dua pesan dari tipe /subscribe
tiba dari pengguna, dan sebagai tanggapan terhadap masing-masing, kami akan membuat entri di piring, karena pada saat memproses pesan-pesan itu, pengguna tidak masuk. Saya curiga bahwa komunikasi dengan monga dalam bentuk yang ada tidak ditulis dengan cara terbaik. Misalnya, pengaturan pengguna dibuat pada saat ia mendaftar. Jika ia mencoba mengubahnya sebelum fakta berlangganan ... bot tidak menjawab, karena kode di aktor naik ke basis data untuk pengaturan, tidak dapat menemukan dan jatuh. Untuk pertanyaan - mengapa tidak membuat pengaturan seperti yang diperlukan, saya menemukan bahwa tidak ada yang dapat mengubahnya jika pengguna belum berlangganan ... Sistem penyaringan pesan entah bagaimana dibuat tidak terlihat, dan bahkan setelah melihat dari dekat ke kode saya tidak bisa mengerti apakah itu awalnya disusun atau ada kesalahan.
Tidak ada daftar artikel yang dikirim ke obrolan, sebaliknya, disarankan agar saya menulis sendiri. Ini mengejutkan saya - secara umum, saya tidak menentang untuk menyeret semua jenis potongan ke dalam proyek, tetapi akan logis untuk menarik hal-hal ini dan mengacaukannya. Tapi tidak, peserta kedua tampaknya telah melupakan segalanya, tetapi mengatakan bahwa daftar di dalam obrolan seharusnya merupakan keputusan yang buruk, dan Anda perlu membuat piring dengan acara seperti "artikel x dikirim ke pengguna x". Kemudian, jika pengguna meminta untuk mengirim artikel baru, itu perlu untuk mengirim permintaan ke database, yang mana dari peristiwa akan memilih peristiwa yang terkait dengan pengguna, masih mendapatkan daftar artikel baru, memfilternya, mengirim kepada pengguna dan melemparkan peristiwa tentang hal itu kembali ke dalam database.
Peserta kedua di suatu tempat menderita ke arah abstraksi, ketika bot tidak hanya akan menerima artikel dari Habr dan mengirim tidak hanya ke telegram.
Saya entah bagaimana mengimplementasikan acara dalam bentuk tablet terpisah pada paruh kedua September. Tidak optimal, tetapi bot setidaknya bekerja dan mulai mengirimi saya artikel lagi, dan perlahan-lahan saya mengetahui apa yang terjadi dalam kode.
Sekarang Anda dapat kembali dulu dan ingat bahwa repositori itu awalnya tidak dibuat oleh saya. Apa yang bisa terjadi begitu? Permintaan kumpulan saya ditolak. Ternyata saya memiliki kode pendek, bahwa saya tidak tahu cara bekerja dalam tim dan saya harus mengedit bug dalam kurva implementasi saat ini, dan tidak memodifikasinya menjadi keadaan yang dapat digunakan.
Saya kesal, melihat sejarah komit, jumlah kode yang ditulis. Saya melihat saat-saat yang semula ditulis dengan baik, dan kemudian patah kembali ...
F * rk itu
Saya ingat artikel You Are Not Google .
Saya pikir tidak ada yang benar-benar membutuhkan ide tanpa implementasi. Saya pikir saya ingin memiliki bot yang berfungsi yang akan bekerja dalam satu salinan pada satu komputer sebagai program java sederhana. Saya tahu bahwa bot saya akan bekerja berbulan-bulan tanpa restart, karena di masa lalu saya menulis bot seperti itu. Jika dia tiba-tiba jatuh dan tidak mengirim artikel berikutnya kepada pengguna, langit tidak akan jatuh ke bumi dan tidak ada bencana yang akan terjadi.
Mengapa saya memerlukan buruh pelabuhan, mongoDB, dan kultus kargo perangkat lunak "serius" lainnya, jika kodenya tidak berfungsi dengan bodoh atau bekerja dengan bengkok?
Saya bercabang proyek dan melakukan semua yang saya inginkan.

Sekitar waktu yang sama, saya mengubah pekerjaan saya dan waktu luang sangat kurang. Di pagi hari saya bangun tepat di kereta, kembali sore hari dan tidak mau melakukan apa-apa lagi. Saya tidak melakukan apa-apa untuk sementara waktu, kemudian saya mengatasi keinginan untuk menyelesaikan bot, dan saya mulai perlahan menulis ulang kode saat mengemudi untuk bekerja di pagi hari. Saya tidak dapat mengatakan bahwa itu produktif: duduk di kereta yang bergetar dengan laptop di pangkuan Anda dan mengintip tumpukan yang meluap dari ponsel Anda sangat tidak nyaman. Namun, waktu di balik penulisan kode itu benar-benar tanpa disadari, dan proyek tersebut perlahan-lahan mulai beralih ke kondisi kerja.
Di suatu tempat jauh di dalam sana ada worm keraguan bahwa mongoDB ingin digunakan, tapi saya pikir ada kerugian yang nyata selain plus dengan penyimpanan negara yang "dapat diandalkan":
- Basis data menjadi titik kegagalan lainnya.
- Kode semakin sulit, dan saya akan menulisnya lebih lama.
- Kode menjadi lambat dan tidak efisien, alih-alih mengubah objek dalam memori, perubahan dikirim ke database dan ditarik kembali jika perlu.
- Ada batasan pada jenis penyimpanan acara di piring terpisah, yang terkait dengan fitur-fitur database.
- Dalam versi percobaan monga ada beberapa batasan, dan jika Anda menabraknya, Anda harus memulai dan mengkonfigurasi mongu untuk sesuatu.
Saya minum Mongu, sekarang keadaan bot hanya disimpan dalam memori program dan dari waktu ke waktu disimpan dalam file dalam bentuk json. Mungkin di komentar mereka akan menulis bahwa saya salah, karena di sinilah Anda harus menggunakannya, dll. Tapi ini proyek saya, pendekatan dengan file sesederhana mungkin dan bekerja secara transparan.
Saya membuang nilai-nilai ajaib seperti -1 dan mengembalikan Option
normal, menambahkan penyimpanan pelat-hash dengan artikel yang dikirim kembali ke objek dengan informasi obrolan. Menambahkan penghapusan informasi tentang artikel yang lebih lama dari lima hari, agar tidak menyimpan semuanya dalam satu baris. Dia membawa logging ke kondisi kerja - log dalam jumlah yang wajar ditulis ke file dan ke konsol. Menambahkan beberapa perintah admin seperti menyimpan keadaan atau mendapatkan statistik seperti jumlah pengguna dan artikel.
Saya memperbaiki banyak hal kecil: misalnya, artikel sekarang menunjukkan jumlah tampilan, suka, tidak suka dan komentar pada saat filter pengguna berlalu. Secara umum, sungguh menakjubkan betapa banyak hal kecil yang harus diperbaiki. Saya menyimpan daftar, mencatat semua "kekasaran" di sana dan memperbaikinya sejauh mungkin.
Misalnya, saya menambahkan kemampuan untuk mengatur semua pengaturan secara langsung dalam satu pesan:
/subscribe /rating +20 /author a -30 /author s -20 /author p +9000 /tag scala 20 /tag akka 50
Dan perintah /settings
menampilkannya dalam formulir ini, Anda dapat mengambil teks darinya dan mengirim semua pengaturan ke teman.
Tampaknya menjadi hal yang sepele, tetapi ada puluhan nuansa serupa.
Pemfilteran artikel yang diterapkan dalam bentuk model linier sederhana - pengguna dapat menetapkan peringkat tambahan untuk penulis dan tag, serta nilai ambang batas. Jika jumlah peringkat penulis, peringkat rata-rata untuk tag dan peringkat aktual artikel lebih besar dari nilai ambang batas, maka artikel ditampilkan kepada pengguna. Anda dapat meminta bot untuk artikel dengan perintah / baru, atau berlangganan bot dan itu akan melempar artikel di PM setiap saat sepanjang hari.
Secara umum, saya punya ide untuk setiap artikel untuk menarik lebih banyak tanda (hub, jumlah komentar, bookmark, dinamika perubahan peringkat, jumlah teks, gambar dan kode dalam artikel, kata kunci), dan pengguna untuk menunjukkan suara ok / tidak ok di bawah masing-masing artikel dan untuk setiap pengguna untuk melatih model, tetapi saya menjadi terlalu malas.
Selain itu, logika kerja tidak akan begitu jelas. Sekarang saya dapat secara manual memberi nilai +9000 untuk patientZero dan dengan nilai ambang +20 saya akan dijamin untuk menerima semua artikelnya (kecuali, tentu saja, saya menaruh -100500 untuk semua tag).
Arsitektur yang dihasilkan cukup sederhana:
- Aktor yang menyimpan status semua obrolan dan artikel. Ini memuat statusnya dari file pada disk dan dari waktu ke waktu menyimpannya kembali, setiap kali ke file baru.
- Seorang aktor yang kadang-kadang bertemu dengan rss feed belajar tentang artikel baru, melihat tautan, mem-parsing, dan mengirimkan artikel ini ke aktor pertama. Selain itu, ia kadang-kadang meminta aktor pertama untuk daftar artikel, memilih orang-orang yang tidak lebih dari tiga hari, tetapi belum diperbarui untuk waktu yang lama, dan memperbaruinya.
- Seorang aktor yang berkomunikasi dengan telegram. Saya masih mengambil parsing pesan sepenuhnya di sini. Dalam cara yang baik, saya ingin membaginya menjadi dua - sehingga satu mem-parsing pesan masuk, dan yang kedua berurusan dengan masalah transportasi seperti meneruskan pesan yang belum terkirim. Sekarang tidak ada pengiriman ulang, dan pesan yang tidak mencapai karena kesalahan hanya akan hilang (kecuali bahwa itu akan ditandai di log), tetapi sejauh ini ini tidak menimbulkan masalah. Mungkin masalah akan muncul jika sekelompok orang berlangganan bot dan saya mencapai batas pengiriman pesan).
Apa yang saya sukai - terima kasih kepada akka, jatuhnya aktor 2 dan 3 secara umum tidak mempengaruhi kinerja bot. Mungkin beberapa artikel tidak diperbarui tepat waktu atau beberapa pesan tidak mencapai telegram, tetapi Akka me-restart aktor dan semuanya terus bekerja lebih jauh. Saya menyimpan informasi bahwa artikel tersebut ditampilkan kepada pengguna hanya ketika aktor telegram menjawab bahwa ia berhasil menyampaikan pesan. Hal terburuk yang mengancam saya adalah mengirim pesan beberapa kali (jika dikirim, tetapi konfirmasi hilang dengan cara yang tidak diketahui). Pada prinsipnya, jika aktor pertama tidak menjaga negara dalam dirinya sendiri, tetapi berkomunikasi dengan semacam database, maka ia juga bisa diam-diam jatuh dan hidup kembali. Saya juga bisa mencoba ketekunan akka untuk mengembalikan keadaan aktor, tetapi implementasi saat ini cocok untuk saya dengan kesederhanaannya. Bukan berarti kode saya sering crash - sebaliknya, saya berusaha keras membuat ini tidak mungkin. Tapi omong kosong terjadi, dan kemampuan untuk membagi program menjadi potongan-potongan-aktor tampak sangat nyaman dan praktis bagi saya.
Menambahkan circle-ci untuk segera mengetahuinya ketika kode rusak. Setidaknya kode telah berhenti dikompilasi. Awalnya, saya ingin menambahkan travis, tetapi hanya menunjukkan proyek saya tanpa yang bercabang. Secara umum, kedua hal ini dapat digunakan secara bebas pada repositori terbuka.
Ringkasan
Sekarang sudah bulan November. Bot ditulis, saya menggunakannya selama dua minggu terakhir dan saya menyukainya. Jika Anda memiliki ide untuk perbaikan - tulis. Saya tidak melihat gunanya memonetisasi - biarkan bekerja dan mengirim artikel yang menarik.
Tautan ke bot: https://t.me/HabraFilterBot
Github: https://github.com/Kright/habrahabr_reader
Kesimpulan kecil:
- Bahkan proyek kecil bisa memakan waktu lama.
- Anda bukan Google. Tidak masuk akal untuk menembak burung pipit dari meriam. Sebuah solusi sederhana dapat bekerja dengan baik.
- Proyek peliharaan sangat cocok untuk bereksperimen dengan teknologi baru.
- Bot telegram ditulis dengan sederhana. Jika bukan karena "kerja tim" dan percobaan dengan teknologi, bot akan ditulis dalam satu atau dua minggu.
- Model aktor adalah hal yang menarik yang berjalan dengan baik dengan multi-threading dan ketahanan kode.
- Sepertinya saya merasakan sendiri mengapa komunitas open source menyukai garpu.
- Basis data bagus karena keadaan aplikasi tidak lagi tergantung pada crash / restart aplikasi, tetapi bekerja dengan database memperumit kode dan memaksakan pembatasan pada struktur data.