Kami merumuskan strategi untuk bekerja dengan kesalahan dalam Bereaksi

Bagaimana cara membuat jatuh lembut?




Saya tidak menemukan panduan komprehensif untuk penanganan kesalahan dalam aplikasi Bereaksi, jadi saya memutuskan untuk berbagi pengalaman yang diperoleh dalam artikel ini. Artikel ini ditujukan untuk pengembang pemula dan dapat menjadi titik awal untuk mensistematisasikan penanganan kesalahan dalam aplikasi.

Masalah dan Penentuan Sasaran


Senin pagi, Anda dengan tenang minum kopi dan membanggakan bahwa Anda telah memperbaiki lebih banyak bug daripada minggu lalu dan kemudian manajer datang berlari dan melambaikan tangannya - β€œkami jatuh, semuanya sangat sedih, kami kehilangan uang”. Anda menjalankan dan membuka Mac Anda, pergi ke versi produksi SPA Anda, buat beberapa klik untuk memutar bug, lihat layar putih dan hanya Yang Mahakuasa yang tahu apa yang terjadi di sana, naik ke konsol, mulai menggali, di dalam komponen t ada komponen dengan nama yang berbicara b, di mana kesalahan tidak dapat membaca getId properti dari undefined. N jam penelitian dan Anda bergegas dengan teriakan menang untuk melempar hotfix. Penggerebekan semacam itu terjadi dengan beberapa frekuensi dan telah menjadi norma, tetapi bagaimana jika saya mengatakan bahwa semuanya bisa berbeda? Bagaimana cara mengurangi waktu untuk kesalahan debug dan membangun proses sehingga klien secara praktis tidak melihat kesalahan perhitungan selama pengembangan yang tidak terhindarkan?

Mari kita periksa agar masalah yang kita hadapi:

  1. Bahkan jika kesalahan tidak signifikan atau terlokalisasi dalam modul, dalam hal apapun seluruh aplikasi menjadi tidak beroperasi
    Sebelum Bereaksi versi 16, pengembang tidak memiliki mekanisme perangkap kesalahan standar tunggal, dan ada situasi ketika korupsi data menyebabkan penurunan rendering hanya pada langkah berikutnya atau perilaku aplikasi aneh. Setiap pengembang menangani kesalahan karena ia terbiasa dengan hal itu, dan model imperatif dengan coba / tangkap umumnya tidak sesuai dengan prinsip deklaratif Bereaksi. Di versi 16, alat Batas Batas muncul, yang mencoba menyelesaikan masalah ini, kami akan mempertimbangkan cara menerapkannya.
  2. Kesalahan hanya direproduksi di lingkungan produksi atau tidak dapat direproduksi tanpa data tambahan.
    Di dunia yang ideal, lingkungan pengembangan sama dengan produksi, dan kami dapat mereproduksi bug apa pun secara lokal, tetapi kami hidup di dunia nyata. Tidak ada alat debugging pada sistem pertempuran. Sulit dan tidak produktif untuk menggali kejadian seperti itu, pada dasarnya Anda harus berurusan dengan kode yang dikaburkan dan kurangnya informasi tentang kesalahan, dan bukan dengan esensi masalah. Kami tidak akan mempertimbangkan masalah tentang cara memperkirakan kondisi lingkungan pengembangan dengan kondisi produksi, namun, kami akan mempertimbangkan alat yang memungkinkan Anda untuk mendapatkan informasi terperinci tentang insiden yang telah terjadi.

Semua ini mengurangi kecepatan pengembangan dan loyalitas pengguna terhadap produk perangkat lunak, jadi saya menetapkan sendiri 3 tujuan paling penting:

  1. Tingkatkan pengalaman pengguna dengan aplikasi jika terjadi kesalahan;
  2. Kurangi waktu antara kesalahan masuk ke produksi dan deteksi;
  3. Mempercepat proses menemukan dan men-debug masalah dalam aplikasi untuk pengembang.

Tugas apa yang perlu diselesaikan?

  1. Menangani kesalahan kritis dengan Batas Kesalahan
    Untuk meningkatkan pengalaman pengguna dengan aplikasi, kita harus mencegat kesalahan UI kritis dan memprosesnya. Dalam kasus di mana aplikasi terdiri dari komponen independen, strategi seperti itu akan memungkinkan pengguna untuk bekerja dengan seluruh sistem. Kami juga dapat mencoba mengambil langkah untuk memulihkan aplikasi setelah macet, jika memungkinkan.
  2. Simpan informasi kesalahan yang diperluas
    Jika terjadi kesalahan, kirim informasi debug ke server pemantauan, yang akan memfilter, menyimpan, dan menampilkan informasi tentang insiden. Ini akan membantu kami dengan cepat mendeteksi dan men-debug kesalahan dengan mudah setelah pemasangan.

Penanganan kesalahan kritis

Dimulai dengan versi 16, React telah mengubah perilaku penanganan kesalahan standar. Sekarang, pengecualian yang tidak tertangkap menggunakan Boundary Kesalahan akan menyebabkan unmount seluruh pohon Bereaksi dan, sebagai akibatnya, menjadi tidak dapat dijalankannya seluruh aplikasi. Keputusan ini diperdebatkan oleh fakta bahwa lebih baik tidak menunjukkan apa pun daripada memberi pengguna kesempatan untuk mendapatkan hasil yang tidak terduga. Anda dapat membaca lebih lanjut di dokumentasi Bereaksi resmi .



Juga, banyak yang bingung dengan catatan bahwa Batas Kesalahan tidak menangkap kesalahan dari penangan acara dan kode asinkron, tetapi jika Anda memikirkannya, penangan mana pun akhirnya dapat mengubah keadaan, berdasarkan pada mana siklus render baru akan dipanggil, yang pada akhirnya akun dapat menyebabkan kesalahan dalam kode UI. Kalau tidak, ini bukan kesalahan kritis untuk UI dan dapat ditangani dengan cara tertentu di dalam handler.

Dari sudut pandang kami, kesalahan kritis adalah pengecualian yang terjadi di dalam kode UI dan jika tidak diproses, maka seluruh pohon Bereaksi akan di-unmount. Kesalahan yang tersisa tidak kritis dan dapat diproses sesuai dengan logika aplikasi, misalnya, menggunakan notifikasi.

Dalam artikel ini, kami akan fokus pada penanganan kesalahan kritis, meskipun fakta bahwa kesalahan tidak kritis juga dapat menyebabkan ketidakmampuan antarmuka dalam kasus terburuk. Pemrosesan mereka sulit untuk dipisahkan menjadi blok umum dan setiap kasus individu memerlukan keputusan tergantung pada logika aplikasi.

Secara umum, kesalahan non-kritis bisa sangat kritis (seperti pelesetan), sehingga informasi tentang mereka harus dicatat dengan cara yang sama seperti untuk kesalahan yang kritis.

Sekarang kami sedang merancang Batas Kesalahan untuk aplikasi sederhana kami, ini akan terdiri dari bilah navigasi, header, dan ruang kerja utama. Cukup sederhana untuk fokus hanya pada penanganan kesalahan, tetapi memiliki struktur khas untuk banyak aplikasi.



Kami memiliki panel navigasi yang terdiri dari 3 tautan, yang masing-masing mengarah ke komponen yang tidak saling bergantung satu sama lain, sehingga kami ingin mencapai perilaku sedemikian sehingga bahkan jika salah satu komponen tidak berfungsi, kami dapat terus bekerja dengan yang lain.

Akibatnya, kami akan memiliki ErrorBoundary untuk setiap komponen yang dapat diakses melalui menu navigasi dan ErrorBoundary umum, yang menginformasikan tentang jatuhnya seluruh aplikasi, jika terjadi kesalahan pada komponen header, panel nav atau di dalam ErrorBoundary, tetapi kami tidak menyelesaikannya proses dan buang lebih lanjut.

Pertimbangkan untuk mendaftarkan seluruh aplikasi yang dibungkus dengan ErrorBoundary

const AppWithBoundary = () => (   <ErrorBoundary errorMessage="Application has crashed">     <App/>   </ErrorBoundary> ) 

 function App() {  return (    <Router>      <Layout>        <Sider width={200}>          <SideNavigation />        </Sider>        <Layout>          <Header>            <ActionPanel />          </Header>          <Content>            <Switch>              <Route path="/link1">                <Page1                  title="Link 1 content page"                  errorMessage="Page for link 1 crashed"                />              </Route>              <Route path="/link2">                <Page2                  title="Link 2 content page"                  errorMessage="Page for link 2 crashed"                />              </Route>              <Route path="/link3">                <Page3                  title="Link 3 content page"                  errorMessage="Page for link 3 crashed"                />              </Route>              <Route path="/">                <MainPage                  title="Main page"                  errorMessage="Only main page crashed"                />              </Route>            </Switch>          </Content>        </Layout>      </Layout>    </Router>  ); } 

Tidak ada keajaiban di ErrorBoundary, itu hanya komponen kelas di mana metode componentDidCatch didefinisikan, yaitu komponen apa pun dapat dibuat ErrorBoundary, jika Anda mendefinisikan metode ini di dalamnya.

 class ErrorBoundary extends React.Component {  state = {    hasError: false,  }  componentDidCatch(error) {    //            this.setState({ hasError: true });  }  render() {    if (this.state.hasError) {      return (        <Result          status="warning"          title={this.props.errorMessage}          extra={            <Button type="primary" key="console">              Some action to recover            </Button>          }  />      );    }    return this.props.children;  } }; 

Inilah yang tampak seperti ErrorBoundary untuk komponen Halaman, yang akan dirender ke dalam blok Konten:

 const PageBody = ({ title }) => (  <Content title={title}>    <Empty className="content-empty" />  </Content> ); const MainPage = ({ errorMessage, title }) => (  <ErrorBoundary errorMessage={errorMessage}>    <PageBody title={title} />  </ErrorBoundary> 

Karena ErrorBoundary adalah komponen Bereaksi reguler, kita dapat menggunakan komponen ErrorBoundary yang sama untuk membungkus setiap halaman dalam handlernya sendiri, cukup dengan memberikan parameter yang berbeda ke ErrorBoundary, karena ini adalah contoh yang berbeda dari kelas, keadaan mereka tidak akan saling bergantung satu sama lain .

PENTING: ErrorBoundary hanya dapat menangkap kesalahan dalam komponen yang ada di bawahnya di hierarki.

Dalam daftar di bawah ini, kesalahan tidak akan dicegat oleh ErrorBoundary lokal, tetapi akan dibuang dan dicegat oleh pawang di atas pohon:

 const Page = ({ errorMessage }) => (  <ErrorBoundary errorMessage={errorMessage}>    {null.toString()}  </ErrorBoundary> ); 

Dan di sini kesalahan ditangkap oleh ErrorBoundary lokal:

 const ErrorProneComponent = () => null.toString(); const Page = ({ errorMessage }) => (  <ErrorBoundary errorMessage={errorMessage}>    <ErrorProneComponent />  </ErrorBoundary> ); 

Setelah membungkus setiap komponen yang terpisah di ErrorBoundary kami, kami mencapai perilaku yang diperlukan, memasukkan kode yang keliru dengan sengaja ke dalam komponen menggunakan tautan3 dan melihat apa yang terjadi. Kami sengaja lupa untuk melewati parameter langkah-langkah:

 const PageBody = ({ title, steps }) => (  <Content title={title}>    <Steps current={2} direction="vertical">      {steps.map(({ title, description }) => (<Step title={title} description={description} />))}    </Steps>  </Content> ); const Page = ({ errorMessage, title }) => (  <ErrorBoundary errorMessage={errorMessage}>    <PageBody title={title} />  </ErrorBoundary> ); 



Aplikasi akan memberi tahu kami bahwa telah terjadi kesalahan, tetapi tidak akan sepenuhnya jatuh, kami dapat menavigasi menu navigasi dan bekerja dengan bagian lain.



Konfigurasi yang sedemikian sederhana memungkinkan kita untuk dengan mudah mencapai tujuan kita, tetapi dalam praktiknya, hanya sedikit orang yang memperhatikan penanganan kesalahan, hanya merencanakan eksekusi aplikasi secara teratur.

Menyimpan Informasi Kesalahan

Sekarang kita telah menempatkan cukup ErrorBoundary di aplikasi kita, maka perlu untuk menyimpan informasi tentang kesalahan untuk mendeteksi dan memperbaikinya secepat mungkin. Cara termudah adalah dengan menggunakan layanan SaaS, seperti Sentry atau Rollbar. Mereka memiliki fungsi yang sangat mirip, sehingga Anda dapat menggunakan layanan pemantauan kesalahan apa pun.

Saya akan menunjukkan contoh dasar pada Sentry, karena hanya dalam satu menit Anda bisa mendapatkan fungsionalitas minimal. Pada saat yang sama, Sentry sendiri menangkap pengecualian dan bahkan memodifikasi console.log untuk mendapatkan semua informasi kesalahan. Setelah itu, semua kesalahan yang akan terjadi dalam aplikasi akan dikirim dan disimpan di server. Sentry memiliki mekanisme untuk menyaring acara, mengaburkan data pribadi, menautkan ke rilis, dan banyak lagi. Kami hanya akan mempertimbangkan skenario integrasi dasar.

Untuk terhubung, Anda harus mendaftar di situs web resmi mereka dan pergi melalui panduan memulai cepat, yang akan segera mengarahkan Anda setelah pendaftaran.

Dalam aplikasi kami, kami hanya menambahkan beberapa baris dan semuanya lepas landas.

 import * as Sentry from '@sentry/browser'; Sentry.init({dsn: β€œhttps://12345f@sentry.io/12345”}); 

Sekali lagi, klik pada tautan / tautan3 di aplikasi kita dan dapatkan layar kesalahan, setelah itu kita pergi ke antarmuka penjaga, tampaknya suatu peristiwa telah terjadi dan gagal di dalam.



Kesalahan secara otomatis dikelompokkan berdasarkan jenis, frekuensi dan waktu terjadinya, berbagai filter dapat diterapkan. Kami memiliki satu peristiwa - kami jatuh ke dalamnya dan di layar berikutnya kami melihat banyak informasi yang berguna, misalnya, tumpukan jejak



dan tindakan pengguna terakhir sebelum kesalahan (remah roti).



Bahkan dengan konfigurasi yang sederhana, kami dapat mengakumulasi dan menganalisis informasi kesalahan dan menggunakannya untuk debugging lebih lanjut. Dalam contoh ini, kesalahan dikirim dari klien dalam mode pengembangan, sehingga kami dapat mengamati informasi lengkap tentang komponen dan kesalahan. Untuk mendapatkan informasi serupa dari mode produksi, Anda juga harus mengkonfigurasi sinkronisasi data rilis dengan Sentry, yang akan menyimpan sourcemap itu sendiri, sehingga Anda dapat menyimpan informasi yang cukup tanpa menambah ukuran bundel. Kami tidak akan mempertimbangkan konfigurasi seperti itu dalam kerangka artikel ini, tetapi saya akan mencoba untuk berbicara tentang jebakan solusi semacam itu dalam artikel terpisah setelah penerapannya.

Hasilnya:

Penanganan kesalahan menggunakan ErrorBoundary memungkinkan kita untuk memperhalus sudut dengan sebagian crash aplikasi, sehingga meningkatkan pengalaman pengguna sistem, dan penggunaan sistem pemantauan kesalahan khusus untuk mengurangi waktu deteksi dan debugging masalah.

Dengan hati-hati memikirkan strategi untuk memproses dan memantau kesalahan aplikasi Anda, di masa depan ini akan menghemat banyak waktu dan usaha. Strategi yang dipikirkan dengan matang terutama akan meningkatkan proses bekerja dengan insiden, dan hanya dengan demikian akan mempengaruhi struktur kode.

PS Anda dapat mencoba berbagai opsi konfigurasi ErrorBoundary atau menghubungkan Sentry ke aplikasi sendiri di cabang feature_sentry, mengganti kunci dengan yang diperoleh saat pendaftaran di situs.

Aplikasi demo Git-hub
Dokumentasi Batas Kesalahan resmi React

Source: https://habr.com/ru/post/id476284/


All Articles