{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Czysty kod"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Gorąco zachęcam do przeczytania książki: Czysty kod. Podręcznik dobrego programisty"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Co to znaczy \"czysty kod\"?\n",
    "\n",
    "Czysty kod to taki zapis kodu, który będzie czytelny/przyjazny dla innych osób (lub samego siebie przy powrocie do danego kodu po kilku miesiącach przerwy)\n",
    "\n",
    "Czysty kod powinien być:\n",
    "* poprawnie sformatowany (dla chętnych dokument PEP 8 opisujący formatowanie kodu w Pythonie https://peps.python.org/pep-0008/)\n",
    "* samoopisywalny - nazwy zmiennych/funkcji powinny opisywać, co dzieje się w danym fragmencie kodu\n",
    "* możliwie krótki i prosty (brak wielokrotnych zagnieżdżeń, wielu różnych wariantów w blokach if-elif-else itp.)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "**1. Nazwy:**\n",
    "\n",
    "* **Znaczące i opisowe:** Nazwy zmiennych, funkcji i klas powinny jasno wskazywać ich przeznaczenie (czyli definiować, z czym mamy doczynienia). Krótka nazwa to nie zawsze dobra nazwa! Przykłady:\n",
    "    * `words` zamiast `w`\n",
    "    * `number_of_ill_patients` jako liczba chorych pacjentów. Jeśli chcielibyśmy przetrzymywać listę/zbiór chorych pacjentów (obiektów posiadających informacje o pacjentach), wtedy możemy skorzystać ze zmiennej `ill_patients`.\n",
    "    * `calculate_sum()` zamiast `calc()`\n",
    "    * nazwy takie jak `x` czy `y` możemy wykorzystywać w takich zastosowaniach jak indeks podczas iterowania pętli\n",
    "* **Konwencja:** Używaj `snake_case` dla nazw zmiennych i funkcji (małe litery, podkreślenia). Klasy piszemy w `CamelCase` (duże litery na początku każdego słowa).\n",
    "* **Unikaj skrótów:**  `unique_elements` zamiast `uni_elem`, wyjątek stanowią skróty, które są jednoznaczne, powszechnie przyjęte i rozumiane przez zdecydowaną większość osób mających styczność z kodem (np. number -> num, dataframe -> df, vocabulary -> vocab, character -> char).\n",
    "\n",
    "**2. Formatowanie:**\n",
    "\n",
    "* **Wcięcia:** Używaj 4 spacji na każde wcięcie.\n",
    "* **Puste linie:** Oddzielaj bloki kodu pustymi liniami dla lepszej czytelności (funkcje, klasy, oraz fragmenty kodu staniowące pewną logiczną spójność).\n",
    "* **Długość linii:** Staraj się, aby linie kodu nie były dłuższe niż 80 znaków.\n",
    "\n",
    "**3. Funkcje:**\n",
    "\n",
    "* **Jedno zadanie:** Każda funkcja powinna wykonywać tylko jedno, konkretne zadanie.\n",
    "* **Krótkie i zwięzłe:** Funkcje powinny być krótkie i łatwe do zrozumienia (tak samo ich nazwy).\n",
    "\n",
    "**4. Komentarze:**\n",
    "* **Podstawowa zasada:** W komentarzu umieszczaj informacje, których nie da się wyrazić w kodzie, a które są ważne. \n",
    "* **Unikaj nadmiaru komentarzy:** Zbyt wiele komentarzy może utrudnić czytanie kodu.\n",
    "\n",
    "**5. Moduły i pakiety:**\n",
    "\n",
    "* **Organizacja:** Dziel duży kod na mniejsze moduły i pakiety, aby ułatwić jego zarządzanie.\n",
    "* **Import:** Importuj tylko niezbędne moduły.\n",
    "\n",
    "**Narzędzia:**\n",
    "\n",
    "* **Linters:** Używaj linterów, takich jak `pylint` lub `flake8`, aby automatycznie sprawdzać styl i jakość kodu.\n",
    "* **Formatery:** Używaj formaterów kodu, takich jak `black` lub `autopep8`, aby automatycznie formatować kod zgodnie z ustalonymi konwencjami.\n",
    "\n",
    "**Pamiętaj:** Celem czystego kodu jest jego zrozumienie i utrzymanie. Inwestycja w czysty kod zaoszczędzi Ci (oraz Twoim współpracownikom) czasu i wysiłku w przyszłości."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Przykład nieczytelnego kodu"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "with open(\"file1.txt\", \"r\") as f:\n",
    "    b = f.readlines()\n",
    "    b = [x.strip() for x in b]\n",
    "    b = set(b)\n",
    "with open(\"file2.txt\", \"r\") as f:\n",
    "    a = f.readlines()\n",
    "    a = [x.strip() for x in a]\n",
    "    a = \" \".join(a)\n",
    "a = a.split()\n",
    "\n",
    "aa = []\n",
    "for a1 in a:\n",
    "\n",
    "    aaa = \"\".join([c for c in a1 if c.isalpha()])\n",
    "    aa.append(aaa)\n",
    "o = []\n",
    "for a2 in aa:\n",
    "    if a2 not in b:\n",
    "        o.append(a2)\n",
    "        \n",
    "print(o)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Przykład wyżej po poprawie"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def remove_nonletters_chars(words):\n",
    "    filtered_words = []\n",
    "\n",
    "    for word in words:\n",
    "        filtered_word = \"\".join([char for char in word if char.isalpha()])\n",
    "        filtered_words.append(filtered_word)\n",
    "    \n",
    "    return filtered_words\n",
    "\n",
    "\n",
    "def get_out_of_vocab_words(text, vocab):\n",
    "    words = text.split()\n",
    "    words = remove_nonletters_chars(words)\n",
    "\n",
    "    out_of_vocab_words = []\n",
    "    for word in words:\n",
    "        if word not in vocab:\n",
    "            out_of_vocab_words.append(word)\n",
    "    \n",
    "    return out_of_vocab_words"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "a\n"
     ]
    }
   ],
   "source": [
    "with open(\"vocabulary.txt\", \"r\") as file:\n",
    "    vocab = file.readlines()\n",
    "    vocab = [x.strip() for x in vocab]\n",
    "    vocab = set(vocab)\n",
    "\n",
    "with open(\"article.txt\", \"r\") as file:\n",
    "    article = file.readlines()\n",
    "    article = [x.strip() for x in article]\n",
    "    article = \" \".join(article)\n",
    "\n",
    "out_of_vocab_words = get_out_of_vocab_words(article, vocab)\n",
    "print(out_of_vocab_words)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### W powyższym kodzie:\n",
    "* zmienne jednoznacznie wskazują \"czym\" są\n",
    "* nazwy funkcji opisują co w nich jest wykonywane\n",
    "* fragmenty kodu są właściwie oddzielone nowymi liniami\n",
    "* kod nie zawiera komentarzy, ponieważ strukturę działania programu dało się wyrazić poprzez nadanie właściwych nazw ziennym oraz funkcjom"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}