diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000000000000000000000000000000000000..26d33521af10bcc7fd8cea344038eaaeb78d0ef5 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/docs/workshops/day_1_sqa.md b/docs/workshops/day_1_sqa.md index ae48cddeb6c38b91d98dfc79af226f487a1ea18c..9165c5f4fca4eddee066903790d6e967ff50536b 100644 --- a/docs/workshops/day_1_sqa.md +++ b/docs/workshops/day_1_sqa.md @@ -1,13 +1,389 @@ # Day 1: Software Quality Assurance (SQA) Overview -* Session 1: 9:00 - 10:15: [Overview of Software Quality Assurance and TDD][1] +* Session 1: 09:00 - 10:15: [Overview of Software Quality Assurance and TDD][1] * Session 2: 10:30 - 11:45: [Test Driven Development][2] * Session 3: 13:00 - 15:00: Hands-on: A small be complete overview of TDD. -* Session 4: 15:30 - 16:30: Overview, Discussion, Lesson learned +* Session 4: 15:30 - 16:30: Overview, Discussion, Lesson learned +## Test-Driven Development (TDD) dan Penjaminan Mutu +Dalam workshop tiga hari ini, anda akan diperkenalkan dengan metode Test-Driven Development (TDD) +dan Behavior-Driven Development (BDD) yang dapat diterapkan sebagai bagian dari proses pengembangan software. +Masing-masing mengedepankan membuat skenario test terlebih dahulu sebelum mulai mengimplementasikan sebuah spesifikasi fitur. -[1]: https://docs.google.com/presentation/d/1fDJF9ocOiDXEqm8WCDX_vWSPoG3L3PNI?rtpof=true&usp=drive_fs +Perbedaannya TDD dan BDD terletak pada pelaku dan proses penyusunan skenario uji coba. +TDD biasanya dibuat oleh tim pengembang dan mengujicobakan komponen _software_ secara _white-box_ ataupun _black-box_. +Sedangkan BDD dibuat melalui kolaborasi antara tim pengembang dengan pemangku kepentingan (_stakeholder_) lain yang bersifat non-teknis, +serta diimplementasikan menggunakan kombinasi program dan prosa bahasa natural. -[2]: https://docs.google.com/presentation/d/1f1uDiI4npQOSih5o0EnqBcJqJL2LBLVk?rtpof=true&usp=drive_fs +TDD akan dibahas secara singkat di hari pertama workshop, +kemudian dibahas lebih mendalam di hari kedua workshop. +Sedangkan BDD akan dibahas di hari ketiga workshop. +Fokus hari ini adalah paparan TDD secara umum dan kegiatan penjaminan mutu. +## Persiapan Workshop + +Persiapkan _tools_ berikut di komputer anda: + +- [Git](https://git-scm.com/) +- [Java JDK 17](https://adoptium.net/temurin/releases/?version=17) +- [IntelliJ IDEA Community Edition](https://www.jetbrains.com/idea/download/) +- [Apache Maven](https://maven.apache.org/download.cgi) +- _Web browser_ seperti [Mozilla Firefox](https://www.mozilla.org/en-US/firefox/new/) + atau [Google Chrome](https://www.google.com/chrome/index.html). +- (Opsional) [Docker dan Docker Compose](https://docs.docker.com/desktop/) apabila ingin menjalankan contoh proyek di dalam _container_. + +Pastikan anda dapat memanggil program-program berikut dari dalam _shell_ favorit anda: + +```shell +git --version +java --version +javac --version +mvn --version +``` + +Hasil pemanggilan program-program di atas seharusnya akan mencetak versi program yang terpasang di komputer anda. + +Selain itu, pastikan anda telah memiliki akun di [GitLab CSUI](https://gitlab.cs.ui.ac.id) +dan [SonarQube CSUI](https://sonarqube.cs.ui.ac.id). Pastikan anda bisa berhasil login ke masing-masing sistem. + +> TODO: Minta peserta untuk membuat _fork_ terlebih dahulu +> dan buat _clone_ Git dari _fork_ yang telah mereka buat. +> Kemudian ingatkan mereka agar menyimpan hasil pekerjaannya ke _fork_. + +Mari mulai dengan menyalin contoh proyek yang akan dibahas di hari pertama workshop, +yaitu [Sitodo PMPL][Sitodo PMPL @ GitLab CSUI]. Buka laman proyek Sitodo PMPL di tautan berikut [(klik)][Sitodo PMPL @ GitLab CSUI], +lalu klik tombol "Fork" untuk membuat salinan proyek tersebut ke dalam akun/_namespace_ GitLab CSUI anda. + +Apabila sudah membuat _fork_ proyek Sitodo PMPL, +buka laman proyek GitLab CSUI _fork_-nya +dan salin repositori kode proyeknya ke suatu lokasi di sistem berkas komputer anda menggunakan Git: + +```shell +# Contoh perintah Git untuk membuat salinan repositori ke dalam sebuah folder +# baru bernama `sitodo-pmpl` di dalam direktori home: +git clone https://gitlab.cs.ui.ac.id/[ akun GitLab CSUI anda ]/sitodo-pmpl.git ~/sitodo-pmpl +``` + +Jika anda lebih nyaman menggunakan IDE seperti IntelliJ IDEA, +anda juga dapat menyalin repositori kode proyek melalui tombol "Get from VCS" seperti yang digambarkan pada _screenshot_ berikut: + + + +Selanjutnya, buka kode proyek menggunakan IntelliJ IDEA. +Kode proyek yang akan dibahas di hari pertama workshop adalah aplikasi "Sitodo PMPL", +yaitu aplikasi Todo List sederhana yang dibangun menggunakan _framework_ Spring Boot +dan digunakan sebagai _running example_ di dalam mata kuliah [Penjaminan Mutu Perangkat Lunak di Fasilkom UI](https://pmpl.cs.ui.ac.id). + +Panduan untuk membuat _build_ serta menjalankan aplikasi dapat dibaca secara mandiri di dokumentasi proyek +([`README.md`](https://gitlab.cs.ui.ac.id/pmpl/examples/sitodo-pmpl/-/blob/main/README.md)). +Namun untuk keperluan workshop hari ini, anda tidak perlu memasang database PostgreSQL yang dibutuhkan oleh aplikasi. +Sebagai gantinya, anda akan menggunakan database _in-memory_ bernama HSQLDB yang akan selalu di-_reset_ setiap kali aplikasi dimatikan. + +Untuk membuat _build_ dan menjalankan aplikasinya secara lokal menggunakan database HSQLDB, +panggil perintah Maven berikut: + +```shell +mvn -DskipTests package +``` + +Kemudian jalankan berkas JAR aplikasinya dengan mengaktifkan _profile_ `hsqldb`: + +```shell +java -D"spring.profiles.active=hsqldb" -jar ./target/sitodo-0.1.3-SNAPSHOT.jar +``` + +Aplikasi akan jalan dan dapat diakses melalui alamat [`http://127.0.0.1:8080`](http://127.0.0.1:8080). +Apabila sudah ada aplikasi lain yang jalan di alamat yang sama (misal: bentrok nomor _port_), +tambahkan parameter `-D"server.port=<nomor port lain>` ketika memanggil perintah Maven. + +Contoh tampilan awal aplikasi dapat dilihat pada _screenshot_ berikut: + + + +Selanjutnya, coba menjalankan fitur utama aplikasi, yaitu membuat todo list. +Tambahkan beberapa _item_ baru ke dalam todo list. +Kemudian perhatikan kondisi-kondisi pada aplikasi, seperti: + +- Alamat (URL) yang tercantum di _address bar_ pada _web browser_ yang anda gunakan. +- Pesan yang muncul setelah anda mengubah status penyelesaian _item_ di dalam todo list. + +## Test Automation + +Langkah-langkah percobaan yang anda lakukan sebelumnya mungkin berbeda dengan apa yang dilakukan oleh kolega anda. +Mungkin anda membuat _item_ baru dengan mengetikkan _item_ tersebut kemudian anda menekan tombol "Enter" di keyboard. +Sedangkan kolega anda tidak menekan tombol "Enter" ketika membuat _item_ baru, melainkan menekan tombol "Enter" yang ada di halaman aplikasi. +Mungkin skenario di atas terdengar sepele, namun menggambarkan adanya potensi proses uji coba dilakukan secara tidak konsisten jika dilakukan oleh manusia. + +Langkah-langkah yang cenderung repetitif dapat diotomasi dan dijalankan oleh bantuan program test. +Pada dasarnya, program tidak akan "lelah" ketika harus menjalankan instruksi yang sama berulang kali. +Bayangkan fitur membuat todo list baru tersebut diuji coba secara otomatis setiap kali ada perubahan baru pada kode proyek. +Tim pengembang dapat lebih fokus untuk menyelesaikan fitur-fitur yang dibutuhkan +dan menyiapkan prosedur uji coba yang dibutuhkan untuk dijalankan secara otomatis. + +Saat ini kode proyek Sitodo PMPL telah memiliki kumpulan _test suite_, +yaitu kumpulan _test case_ yang dapat dijalankan sebagai program test oleh _test runner_ terhadap subjek uji coba. +Subjek uji coba berupa _software_/sistem secara utuh (seringkali disebut sebagai _System/Software Under Test_ atau SUT). + +### Unit Test + +Mari coba lihat contoh _test suite_ yang termasuk dalam golongan "unit test". +"Unit" dalam konteks ini mengacu pada komponen terkecil pada _software_. +Sebagai contoh, fungsi, metode (_method_), hingga modul dapat diklasifikasikan sebagai "unit". + +Jalankan perintah Maven berikut di _shell_ untuk menjalankan _test suite_ bertipe `unit`: + +```shell +mvn test -D"groups=unit" -D"spring.profiles.active=hsqldb" +``` + +> Catatan: Bagi pengguna IntelliJ IDEA, anda dapat membuat Run Configuration untuk menjalankan perintah Maven di atas. + +Maven akan menjalankan _test suite_ yang berisi kumpulan _test case_ dari grup `@Tag("unit")` di kode test. +Hasil eksekusi setiap _test case_ kemudian dilaporkan ke _standard output_ +dan berkas-berkas laporan di folder `target/surefire-reports`. + +### Functional Test + +Sekarang coba jalankan _test suite_ untuk menguji "fungsionalitas" pada SUT, +atau seringkali dikenal sebagai "functional test". +Pengujian dilakukan terhadap SUT yang sudah di-_build_ dan berjalan di sebuah _environment_. + +Jalankan perintah Maven berikut di _shell_: + +```shell +mvn test -D"groups=e2e" -D"spring.profiles.active=hsqldb" +``` + +Serupa dengan contoh eksekusi sebelumnya, Maven akan menjalankan _test suite_ yang berisi kumpulan _test case_ dari grup `@Tag("e2e")` di kode test. +_Test suite_ jenis ini disebut sebagai _functional test_, dimana _test case_ akan menggunakan _web browser_ untuk menjalankan aksi-aksi pengguna terhadap SUT. +Pada contoh aplikasi Sitodo PMPL, aksi-aksi pengguna dijalankan pada _web browser_ secara otomatis dengan bantuan Selenium. +Oleh karena itu, anda akan melihat _web browser_ anda bergerak secara otomatis ketika _functional test_ berjalan. + +Jika anda ingin menjalankan seluruh _test suite_, +maka perintah Maven yang dapat anda panggil adalah sebagai berikut: + +```shell +mvn test -D"spring.profiles.active=hsqldb" +``` + +_Unit test_ akan berjalan sangat cepat dimana durasi tiap eksekusi _test case_ berada dalam rentang kurang dari 1 detik per _test case_. +Sedangkan _functional test_ akan memakan waktu lebih lama karena ada _overhead_ untuk menyiapkan dan menyimulasikan aksi pengguna di _web browser_. + +## Laporan Hasil Test + +_Test suite_ pada proyek Sitodo PMPL dibuat dengan bantuan _test framework_ JUnit 5. +Sebagai _test framework_, JUnit 5 memberikan kerangka kepada developer agar dapat membuat _test suite_ sesuai dengan konvensi JUnit 5. +Selain itu, JUnit 5 juga menyediakan _test runner_ untuk menjalankan _test suite_ +serta dapat melakukan _test reporting_ untuk mencatat hasil eksekusi _test suite_. + +Laporan hasil test dapat dilihat di folder `target/surefire-reports`. +Anda dapat temukan berkas-berkas laporan dalam format teks polos (`.txt`) dan XML. +Berkas laporan teks polos hanya menyebutkan berapa banyak _test case_ yang berhasil dan gagal pada sebuah _test suite_. +Sedangkan berkas laporan XML mengandung informasi yang jauh lebih rinci, +seperti informasi _environment_ yang menjalankan _test case_ +hingga cuplikan log _standard output_ ketika menjalankan _test case_. + +Berkas-berkas laporan tersebut dapat dikumpulkan dan diberikan ke _tools_ lain. +Sebagai contoh, _pipeline_ CI/CD GitLab dapat membaca berkas laporan XML JUnit. +Berkas-berkas laporan XML tersebut akan dipetakan menjadi daftar _test case_ yang diasosiasikan ke _pipeline_ CI/CD GitLab. +Contoh tampilan daftar tersebut dapat dilihat pada _screenshot_ berikut ini: + + + +## Siklus TDD + +Proses pengembangan yang menerapkan metode TDD akan melalui tiga fase berikut secara iteratif ketika mengimplementasikan sebuah fitur, +yaitu: + +1. Fase "Red" +2. Fase "Green" +3. Fase "Refactor" + +Fase "Red" adalah fase awal dimana developer mengembangkan _test case_ untuk implementasi sebuah fitur terlebih dahulu. +"Red" mengacu pada status "_fail_"/gagal yang dilaporkan oleh _test runner_ secara visual. +Tentu saja hasil test akan gagal karena kode implementasi masih kosong. + +Setelah mengembangkan _test case_ yang dibutuhkan, developer masuk ke fase "Green" +dimana developer mengembangkan kode implementasi fitur sehingga _test case_ berhasil ("_pass_"). + +Fase terakhir, yaitu fase "Refactor", bertujuan untuk meningkatkan kualitas kode +serta menjaga agar _test case_-_test case_ yang sudah ada tidak kembali gagal ("_fail_"). + +### Latihan Singkat: Implementasi Fitur Sederhana + +> TODO: Tulis instruksi latihan yang membimbing peserta mengerjakan sebuah fitur sederhana +> pada Sitodo PMPL menggunakan metode TDD. +> Fitur sederhana yang akan dikerjakan: Visitor Counter (menghitung jumlah kunjungan ke situs). + +## Analisis & Laporan Kualitas Kode + +> TODO: Tambah paragraf pengantar. Jelaskan alternatif-alternatif static analysis seperti +> CodeQuality yang tersedia di CI/CD GitLab dan SonarQube. + +Cara kerja SonarScanner adalah sebagai berikut: + +1. SonarScanner melakukan analisis terhadap kode program + dan mengumpulkan laporan-laporan dari _test framework_ + serta hasil analisis dari _tools_ lain yang didukung oleh SonarQube. +2. Hasil analisis SonarScanner dan laporan-laporan lainnya diagregatkan sebelum dikirim ke SonarQube. +3. SonarQube menerima laporan agregat dari SonarScanner + dan mengolahnya untuk menentukan kualitas kode. +4. Hasil pengolahan SonarQube akan ditampilkan di laman proyek analisis terkait. + +Berikut ini adalah contoh tampilan _dashboard_ yang menampilkan gambaran besar kualitas kode proyek Sitodo PMPL di [SonarQube][SonarQube Sitodo PMPL]: + + + +Dapat dilihat bahwa proyek Sitodo PMPL memenuhi kriteria kualitas kode bawaan SonarQube yang dikenal sebagai [_Quality Gate_](https://docs.sonarsource.com/sonarqube/latest/user-guide/quality-gates/). +Menurut dokumentasi SonarQube, sebuah proyek dianggap lulus _Quality Gate_ jika: + +- Tidak ada _bug_ baru pada kode. +- Tidak ada celah keamanan baru pada kode. +- Semua isu terkait keamanan ("_security hotspot_") sudah ditindaklanjuti. +- Perubahan baru pada kode mengandung _technical debt_ di bawah batasan tertentu. +- Perubahan baru pada kode mengandung duplikasi kode di bawah batasan tertentu. +- Perubahan baru pada kode di-_cover_ oleh test. + +Prinsip yang ditekankan oleh kriteria _Quality Gate_ adalah "Clean as You Code". +Apabila sudah sempat memenuhi _Quality Gate_, maka selanjutnya tim pengembang diharapkan untuk, minimal, +mempertahankan kualitas kode yang telah tercapai di setiap perubahan yang dilakukan. +Jika sudah berhasil mempertahankan kualitas, maka tim pengembang juga diharapkan untuk memperbaiki isu-isu yang sudah sempat terdeteksi. + +### Technical Debt & Code Smells + +Dengan waktu yang terbatas, mari fokus mengulas tiga contoh _code smell_ berikut, yaitu: + +- Duplikasi Kode +- for & foreach Loop +- Cyclomatic/Cognitive Complexity + +> TODO: Jelaskan singkat masing-masing contoh _code smell_. + +### Latihan Singkat: Mengurangi Tingkat Kompleksitas Kode Melalui Refactoring + +```java +public String computeMotivationMessage(TodoList todoList) { + List<TodoItem> items = todoList.getItems(); + final long totalItems = (items != null) ? items.size() : 0; + final long totalFinishedItems = (items != null) ? + items.stream().filter(TodoItem::getFinished).count() : 0; + + LOG.debug("Total Items: {}; Total Finished Items: {}", totalItems, totalFinishedItems); + + String output = ""; + + if (totalItems == 0) { + output += emptyListMessage; + } else if (totalItems < manyItemsThreshold) { + output += fewItemsMessage; + + if (totalFinishedItems == totalItems) { + output += " " + allFinishedMessage; + } else if (totalFinishedItems == 0) { + output += " " + noFinishedMessage; + } else if (totalFinishedItems < totalItems && totalFinishedItems >= totalItems / 2) { + output += " " + halfFinishedMessage; + } else { + output += someFinishedMessage; + } + } else { + output += manyItemsMessage; + + if (totalFinishedItems == totalItems) { + output += " " + allFinishedMessage; + } else if (totalFinishedItems == 0) { + output += " " + noFinishedMessage; + } else if (totalFinishedItems < totalItems && totalFinishedItems >= totalItems / 2) { + output += " " + halfFinishedMessage; + } else { + output += someFinishedMessage; + } + } + + LOG.debug("Resulting output: {}", output); + + return output; +} +``` + +Implementasi fungsi `computeMotivationMessage` di atas memiliki nilai Cognitive Complexity sebesar 17. +Tingkat kompleksitas pada kode dapat dikurangi dengan cara menyederhanakan bagian yang mengandung percabangan. + +Dapat dilihat bahwa terdapat percabangan yang mengandung duplikasi, +yaitu pembuatan pesan motivasi berdasarkan jumlah tugas yang tersisa. +Bagian tersebut dapat dienkapsulasi ke dalam sebuah fungsi baru. +Dalam literatur _refactoring_, prosedur melakukan enkapsulasi satu atau lebih _statement_ ke dalam sebuah fungsi disebut sebagai _Extract Method_. + +Buka kode Java terkait yang mengandung sumber `computeMotivationMessage` menggunakan IntelliJ IDEA +kemudian _highlight_ seluruh blok percabangan yang diawali oleh `if (totalFinishedItems == totalItems) {`, +seperti yang terlihat pada _screenshot_ berikut dari IntelliJ: + + + +Apabila blok tersebut sudah di-_highlight_, +klik kanan dan pilih opsi Refactoring > Extract Method. +Kemudian berikan nama fungsi yang mengandung hasil enkapsulasi, +lalu pilih opsi untuk mengganti ("_Replace_") semua blok percabangan yang duplikat dengan pemanggilan fungsi baru. + +> Note: _Extract Method_ juga dapat dilakukan melalui _keyboard shortcut_ Ctrl+Alt+M di IntelliJ. + +Versi akhir fungsi `computeMotivationMessage` setelah _refactoring_ adalah sebagai berikut: + +```java +public String computeMotivationMessage(TodoList todoList) { + List<TodoItem> items = todoList.getItems(); + final long totalItems = (items != null) ? items.size() : 0; + final long totalFinishedItems = (items != null) ? + items.stream().filter(TodoItem::getFinished).count() : 0; + + LOG.debug("Total Items: {}; Total Finished Items: {}", totalItems, totalFinishedItems); + + String output = ""; + + if (totalItems == 0) { + output += emptyListMessage; + } else if (totalItems < manyItemsThreshold) { + output += fewItemsMessage; + output = getMotivationMessageByTotalItems(totalFinishedItems, totalItems, output); + } else { + output += manyItemsMessage; + output = getMotivationMessageByTotalItems(totalFinishedItems, totalItems, output); + } + + LOG.debug("Resulting output: {}", output); + + return output; +} + +private String getMotivationMessageByTotalItems(long totalFinishedItems, long totalItems, + String output) { + if (totalFinishedItems == totalItems) { + output += " " + allFinishedMessage; + } else if (totalFinishedItems == 0) { + output += " " + noFinishedMessage; + } else if (totalFinishedItems < totalItems && totalFinishedItems >= totalItems / 2) { + output += " " + halfFinishedMessage; + } else { + output += someFinishedMessage; + } + + return output; +} +``` + +Untuk memastikan kegiatan _refactoring_ tidak merusak kode implementasi sehingga menyebabkan regresi, +jalankan kembali _test suite_ yang menguji kebenaran implementasi fungsi `computeMotivationMessage`. +Jika hasil eksekusi _test suite_ sukses ("pass"), +maka dapat disimpulkan _refactoring_ berhasil dilakukan tanpa merusak kebenaran implementasi. +Sebaliknya, jika ternyata hasilnya gagal, +maka ada kesalahan pada _refactoring_ yang dilakukan. + +## Penutup + +> TODO: Tulis paragraf meringkas kegiatan hari ini dan berikan _preview_ agenda hands-on hari berikutnya. + +[1]: https://docs.google.com/presentation/d/1fDJF9ocOiDXEqm8WCDX_vWSPoG3L3PNI?rtpof=true&usp=drive_fs +[2]: https://docs.google.com/presentation/d/1f1uDiI4npQOSih5o0EnqBcJqJL2LBLVk?rtpof=true&usp=drive_fs +[Sitodo PMPL @ GitLab CSUI]: https://gitlab.cs.ui.ac.id/pmpl/examples/sitodo-pmpl.git +[SonarQube Sitodo PMPL]: https://sonarqube.cs.ui.ac.id/dashboard?id=pmpl_examples_sitodo-pmpl_AYtLlyeZ94kwVhMRxVyD diff --git a/docs/workshops/day_3_bdd.md b/docs/workshops/day_3_bdd.md index a4d611a668c8e1db4dc9f879269d25af6884c83e..665ff9f30b5897a2a00c7873479f142131adda7b 100644 --- a/docs/workshops/day_3_bdd.md +++ b/docs/workshops/day_3_bdd.md @@ -332,7 +332,7 @@ Berikut ini adalah daftar referensi terkait XPath yang direkomendasikan: - [XPath | Mozilla Developer Network](https://developer.mozilla.org/en-US/docs/Web/XPath) - [XPath Cheatsheet](https://devhints.io/xpath) -- + ### Latihan Singkat: Membuat Step Definition Baru > TODO: Tambah pengantar diff --git a/docs/workshops/images/day_1_sqa_-_branch_to_refactor.png b/docs/workshops/images/day_1_sqa_-_branch_to_refactor.png new file mode 100644 index 0000000000000000000000000000000000000000..55035b5cd20f99adda6bfec14a2ec558ab3c2dcd Binary files /dev/null and b/docs/workshops/images/day_1_sqa_-_branch_to_refactor.png differ diff --git a/docs/workshops/images/day_1_sqa_-_get_from_vcs.png b/docs/workshops/images/day_1_sqa_-_get_from_vcs.png new file mode 100644 index 0000000000000000000000000000000000000000..dec6ca77a9096788728e26b90e3d5a4a4853a7d5 Binary files /dev/null and b/docs/workshops/images/day_1_sqa_-_get_from_vcs.png differ diff --git a/docs/workshops/images/day_1_sqa_-_gitlab_pipeline_tests_widget.png b/docs/workshops/images/day_1_sqa_-_gitlab_pipeline_tests_widget.png new file mode 100644 index 0000000000000000000000000000000000000000..2f1d0c2d573d702402bc36b7a9034c56b04949c2 Binary files /dev/null and b/docs/workshops/images/day_1_sqa_-_gitlab_pipeline_tests_widget.png differ diff --git a/docs/workshops/images/day_1_sqa_-_main_page_sitodo.png b/docs/workshops/images/day_1_sqa_-_main_page_sitodo.png new file mode 100644 index 0000000000000000000000000000000000000000..d14095d491761a5948cfb93904617084f834a39a Binary files /dev/null and b/docs/workshops/images/day_1_sqa_-_main_page_sitodo.png differ diff --git a/docs/workshops/images/day_1_sqa_-_sonarqube_sitodo_pmpl.png b/docs/workshops/images/day_1_sqa_-_sonarqube_sitodo_pmpl.png new file mode 100644 index 0000000000000000000000000000000000000000..7fcb0151b61223123af2087976eb9985e91c0948 Binary files /dev/null and b/docs/workshops/images/day_1_sqa_-_sonarqube_sitodo_pmpl.png differ