Head of Content w Kodilli

Jako Head of Content w Kodilli projektowałem i rozwijałem kursy programowania, koordynując cały proces — od pomysłu, przez zespół, treści i wideo, po analizę KPI — czyli zarządzałem edukacyjną machiną, która miała nauczyć ludzi kodować i jeszcze zrobić to w sposób zrozumiały.

Co robiłem

  • Projektowałem i rozwijałem kursy online z Web Developmentu, Pythona i Data Science, od pierwszej koncepcji po finalne wdrożenie na platformę.
  • Zarządzałem zespołem contentowym (ok. 4 osób) oraz współpracowałem z autorami, testerami i ekspertami merytorycznymi, pilnując, by całość miała sens i nie kłóciła się z logiką lub rzeczywistością.
  • Tworzyłem materiały dydaktyczne: struktury kursów, treści lekcji, scenariusze nagrań oraz wideo tutoriale.
  • Analizowałem KPI, feedback od kursantów i wyniki egzaminów, żeby kursy nie tylko wyglądały dobrze na papierze, ale faktycznie działały.
  • Koordynowałem prace związane z rozwojem platformy i CMS, dbając o spójność UX w całym ekosystemie kursów.
  • Współpracowałem z marketingiem, IT i obsługą klienta, łącząc ich perspektywy w jedną sensowną całość (zaskakująco często).

Co z tego wynikało

  • Powstały kompletne, dopracowane kursy programowania, z których korzystały tysiące osób uczących się Web, Pythona i Data Science.
  • Usprawniłem procesy tworzenia treści — kursy były wdrażane szybciej, a ich struktura była bardziej spójna.
  • Analizy KPI i feedbacków pozwoliły zwiększyć skuteczność nauczania i zmniejszyć liczbę punktów, w których kursanci wymiękali.
  • Zbudowałem zespół, który potrafił dostarczać treści jakościowe, powtarzalne i odporne na chaos.
  • Wpłynąłem na rozwój platformy — od CMS po UX — poprawiając doświadczenie użytkownika na każdym etapie nauki.

Proces pracy

Każdy kurs przechodził pełen cykl:
research → koncepcja → struktura → treści → testowanie → iteracje → wdrożenie → analiza KPI → poprawki → kolejne iteracje.
W skrócie: edukacyjny DevOps.

Przykładowe treści

Kurs Pythona (fragment)

Funkcje i interakcja z użytkownikiem

  • nauczysz się tworzyć własne funkcje,
  • dodasz do nich argumenty, by stały się jeszcze lepsze,
  • przekonasz się jak można uczynić nasze programy interaktywnymi,
  • dowiesz się jak radzić sobie z błędami w kodzie.

Czym sssssą funkcje

Można pisać programy bez własnych funkcji? Tak, ale czy zostaniesz prawdziwym programistą bez ich znajomości? Absolutnie nie. To jeden z filarów języków programowania, który po prostu musisz poznać.

Funkcje są blokami kodu. Przyjmują od nas jakieś początkowe dane, przeprowadzają na nich operacje i zwracają wynik. Pomaga to zautomatyzować wiele rzeczy, optymalizować tworzenie programów i porządkować kod. Raz napisana funkcja może być używana wielokrotnie, z różnymi danymi wsadowymi.

Załóżmy, że Twój ulubiony szef znów wysyła Cię na zakupy i daje Ci listę pysznych serów (to dane początkowe).

Co musisz zrobić? Wyjść z biura, wejść do sklepu, wybrać odpowiednie produkty z listy, włożyć je do koszyka i zapłacić (zestaw operacji).

Rezultatem tego działania są reklamówki pełne goudy i masdamera (wynik).

Właśnie tak działa funkcja. Mając opracowany zestaw czynności, nic nie stoi na przeszkodzie, by wykorzystać go także robiąc zakupy dla siebie. Wystarczy podać inne dane początkowe, a efektem będzie kupienie mielonki i jajek.

Proste?

Do tej pory wykorzystywaliśmy metody i funkcje już zadeklarowane w języku Python jak np. print(). W tym module przyszedł czas na Ciebie i funkcje, które napiszesz samodzielnie.

Wprowadzenie do funkcji

Definicja i wywołanie

Funkcje dostępne są w wielu językach. W Pythonie definiujemy je następująco:

def demo_function():
    print("I am inside of a function!")

Zauważ, że rozpoczynamy od komendy def. Potem piszemy nazwę funkcji z nawiasami, dwukropek (:), a następnie jej ciało w kolejnych liniach. Ciało jest blokiem, który rządzi się swoimi prawami (dla przypomnienia – blok to fragment kodu, w którym wszystkie linijki mają takie same wcięcia, zatem pamiętaj o odpowiednim formatowaniu za pomocą spacji).

To jednak nie wszystko. Funkcja jest blokiem kodu, który wykonuje się wyłącznie wtedy, gdy jest wywołany.

Jak to zrobić? Poprzez użycie nazwy i nawiasów okrągłych.

demo_function()

Po wywołaniu powyższej funkcji zobaczysz taki wynik:

>> I am inside of a function!

Świetnie, udało Ci się stworzyć pierwszą funkcję i ją nazwać. A skoro już jesteśmy w temacie “nazywania”. Podobnie jak w przypadku zmiennych, oprócz stosowania się do pewnych z góry narzuconych generalnych zasad, chcemy trzymać się dobrych praktyk programowania. Według nich – nazwa powinna opisywać, czym funkcja się zajmuje. Mając np. print_hello_world(), od razu możemy wywnioskować czego się po niej spodziewać.

Istnieją też inne oficjalne wytyczne PEP8, z którymi warto się zapoznać i stosować.

Ćwiczenie

Stwórz funkcję, w której dodasz dwie liczby i wyświetl to na ekranie. Jak ją nazwiesz? Funkcję stworzysz z użyciem def. W ciele umieść operację i funkcję print.

Widoczność zmiennej

Gdy omawialiśmy zmienne, stwierdziliśmy, że przechowują one określoną wartość. Teraz rozszerzymy nieco tę wiedzę. Musisz zmierzyć się z faktem, że zmienna może mieć różną wartość, w zależności od miejsca, w którym się znajduje.

Dlaczego tak jest? Otóż zmienna ma zakres, w którym jest widoczna (ang. scope) i tylko tam możemy na niej działać. Tym zakresem jest blok, w którym została zadeklarowana.

Czy to znaczy, że zmienna może przestać być widoczna i że coś ją zasłania? Tak.

Zobaczmy, jak to wygląda na przykładzie:

a = 1

def scope_demo():
    a = 2
    print(a)

scope_demo()
print(a)

Program wypisze dwie wartości. A wiesz jakie? Koniecznie sprawdź to, wpisując kod w swoim edytorze.

W ciele funkcji scope_demo() wartość zmiennej a jest równa 2. Dlatego na ekranie najpierw pojawi się 2. Jednak potem drukuje się 1. Dlaczego? Po wykonaniu się funkcji wróciliśmy do głównego bloku (którego liczba spacji od krawędzi wynosi zero). Tutaj wartość a nadal jest równa 1.

Warto poświęcić chwilę na zrozumienie tej koncepcji, żeby uniknąć niespodzianek w przyszłości.

Podsumowując: jeśli zadeklarujemy zmienną w bloku, jest ona widoczna tylko dla tego bloku (co się dzieje w Camelot, zostaje w Camelot – wiesz, o co chodzi).

Zwracana wartość

Jeśli hasło “funkcja” kojarzysz z “matematyczna”, to jesteś na dobrym tropie. Programistyczne funkcje nawiązują do matematycznych także w tym, że zwracają pewne wartości.

Bo tak naprawdę jaki jest pożytek z funkcji? Mają one do wykonania jakieś zadanie, a nas najbardziej interesuje jego wynik.

W ciele funkcji to, co ma zostać zwrócone jako rezultat, podajemy po komendzie return.

Idziemy na zakupy i mamy listę rzeczy, których potrzebujemy. Jako rezultat oczekujemy koszyka pełnego produktów (w tym przypadku będą to wirtualne zakupy w postaci tekstu, czyli stringu):

def shopping():
    shopping_items = [
        "jajka",
        "bułka",
        "ser feta",
        "masło",
        "pomidor"
    ]
    shopping_cart = "Koszyk zawiera: "
    for item in shopping_items:
        shopping_cart += item + '
'
    return shopping_cart

print(shopping())
>> Koszyk zawiera: jajka
>> bułka
>> ser feta
>> masło
>> pomidor

Jak widzisz, jesteśmy w sklepie i właśnie tam uzupełniamy koszyk, który potem postawimy przy kasie. Tłumacząc to na język programowania, tworzymy sobie zmienną shopping_cart(wózek sklepowy) i tę właśnie zmienną zwracamy jako rezultat funkcji. Dlatego też mogliśmy jej użyć bezpośrednio przy wywołaniu funkcji print.

Dodatkowo rezultat funkcji da się przypisać do zmiennej. Wtedy nasz koszyk zakupów moglibyśmy zdefiniować tak:

shopping_result = shopping()
print(shopping_result)

Brak rezultatu?

Funkcja zawsze zwraca rezultat i nie ma innej możliwości. Nie zawsze jednak go potrzebujemy i wtedy możemy pominąć użycie return. W takiej sytuacji kompilator sam stworzy nam pod koniec funkcji taką linijkę

return None

Wtedy funkcja zwróci ten charakterystyczny dla Pythona typ pusty, czyli None.

Z punktu widzenia składniowego, zapisanie funkcji bez return jest jak najbardziej poprawne, np. tak:

def no_result_function():
    print("I am just printing I love you")
    print("and returning nothing to you!")

Pominięcie słowa return jest równoznaczne z zapisem zwrócenia None wprost

return None

albo pustą komendą return

return

Ćwiczenie

Jakiego typu jest None? Przetestuj to, wywołując funkcję type na rezultacie funkcji, która nic nie zwraca. Niespodzianka?

Więcej wyników

Ile rezultatów może mieć funkcja? Tylko jeden, podobnie jak matematyczna. Dla każdego x jest tylko jeden y. Obiekty w Pythonie mają jednak pewną właściwość, która pozwala radzić sobie z sytuacją, kiedy potrzebujemy „wydostać” nieco więcej elementów z funkcji. Pamiętasz kolekcje? Tak, one też mogą być rezultatem funkcji. Zatem spokojnie możemy zadeklarować funkcję, która zwróci nam kilka elementów krotki lub listy.

def day_times():
    return "morning", "afternoon", "evening", "night"

times = day_times()
print(times)
print(type(times))

Choć wydaje się, że mamy więcej niż jeden rezultat, to tak naprawdę jest tutaj jedna krotka, w której po prostu pominęliśmy nawiasy okrągłe podczas definicji.

Staje się to jasne, gdy sprawdzamy typ tego obiektu. Wywołanie tego kodu zwróci:

>> ('morning', 'afternoon', 'evening', 'night')
>> <class 'tuple'>

Taka krotka może zostać rozpakowana automatycznie, w zwykły, znany Ci sposób.

first, second, third, fourth = day_times()
print("Trzeci element to %s" % third)
>> Trzeci element to evening

Jest dobrze, ale może być jeszcze lepiej, kiedy poznamy argumenty funkcji.

Infografiki

Napisz do mnie

Jeśli chcesz stworzyć treści, które opowiadają historię i zostawiają ślad — odezwij się.

Aby wypełnić ten formularz, włącz obsługę JavaScript w przeglądarce.