Jak dobrze podzielić program na moduły lub mikroserwisy?

Jak dobrze podzielić program na moduły lub mikroserwisy?
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
3

Tak mi się nasunęło na myśl podczas czytania tej dyskusji, że właściwie nie istnieje jakaś ogólna, przyjęta definicja architektury mikroserwisowej, więc równie dobrze wszyscy mogą mieć rację. To z czym się zetknąłem, to "zbiór małych, luźno powiązanych usług, o dobrze zdefiniowanych API". Natomiast jeżeli patrzymy na to nieco szerzej, to jest to wyniesienie ogólnie znanych zasad SOLID do poziomu osobnych usług. Nic nie stoi na przeszkodzie, żeby zamiast mieć spaghetti code mieć spaghetti microservices i być zmuszonym, do zmiany 15 usług w momencie implementowania prostej funkcji systemu. Nic nie stoi na przeszkodzie, żeby mieć dobrą architekturę na poziomie modułów monolitu.

Nie ma też jasnej odpowiedzi na pytanie, czy "mikroserwisy są lepsze od monolitu, czy odwrotnie". Każde z tych rozwiązań ma swoje zalety i koszty. W przypadku mikroserwisów dość oczywistym kosztem jest np. konieczność posiadania CI/CD, bardziej złożonego środowiska uruchomieniowego. Zalety, już wymieniał @Krolik , ale dość często korzysta się też z łatwości zarządzania separacją usług, bo tutaj nie da się na szybko sięgnąć do bazy danych innej usługi i wyciągnąć trochę danych tak jak nam się w danym momencie podoba. Skalowalność w porównaniu z monolitem, nawet po użyciu wszelkich możliwych sztuczek też jest nieporównywalna (chociażby dlatego, że mała usługa uruchamia się szybciej niż duża usługa). Natomiast pozostaje pytanie, czy w danym projekcie zalety któregoś z tych podejść przewyższają koszty. Problem polega na tym, że dość często decyzja o użyciu jakiejś technologii następuje po tym, jak ktoś obejrzał filmik, przeczytał książkę, czy pojechał na jakąś konferencję i nasłuchał się o zaletach danego podejścia, natomiast rzadko kiedy usłyszał o wadach/kosztach. Patrząc na mikroserwisy te koszty są spore i oprócz bardziej złożonego deploymentu, będzie to konieczność głębszego zrozumienia problemu przed rozpoczęciem pracy, rezygnacja z ACID i konieczność walki z eventual consistency, sagami, czy innym event sourcing. Trzeba będzie się zastanowić jak zarządzać wspólnymi częściami kodu itd.

AN
No nie. Riddle Ci napisze, że to już nie jest mikroserwis jak masz go słabo napisanego.
SL
  • Rejestracja:około 7 lat
  • Ostatnio:około 19 godzin
  • Postów:857
2
Riddle napisał(a):

Do wszystkich którzy myślą że mikroserwisy mogą od siebie zależeć: tematy do powtórzenia: 1. enkapsulacja 2. dependency inversion 3. loose-coupling.

Jeśli serwisy od siebie nie zależą to nie są mikroserwisami tylko osobnymi systemami. Wywołanie jakiegokolwiek zapytania to już zależność i każdy szczegół w kontrakcie ma znaczenie

AN
Nie, nie będą to mikroserwisy i nie wiesz co to TDD jak 100% programistów!
Riddle
Administrator
  • Rejestracja:ponad 14 lat
  • Ostatnio:36 minut
  • Lokalizacja:Laska, z Polski
  • Postów:10032
0
slsy napisał(a):

Jeśli serwisy od siebie nie zależą to nie są mikroserwisami tylko osobnymi systemami.

No właśnie nie, bo żeby były osobnymi systemami to musiałyby się między sobą nie komunikować, a mikroserwisy się komunikują między sobą.

slsy napisał(a):

Wywołanie jakiegokolwiek zapytania to już zależność i każdy szczegół w kontrakcie ma znaczenie

To nie jest prawda że "jakiekolwiek zapytanie" to już zależność. Można wysłać zapytanie które nie jest zależnością - jeśli ta komunikacja spełnia pewne kryteria.

Krok wstecz

Pomiędzy klasami, programami, modułami, aplikacjami i serwisami które wchodzą między sobą w interakcję (czyt. komunikują się ze sobą), mogą to robić na dwa sposoby:

  • Mogą wejść ze sobą w interakcję w taki sposób, że polegają na sobie (wiedzą o sobie, wołają się bezpośrednio, zmiana w jednym wymaga zmian w drugim, awaria jednego koniecznie oznacza awarię drugiegio)
  • Mogę wejść ze sobą w interakcję w taki sposób, że nie polegają na sobie (nie wiedzą o sobie - albo wiedzą prawie nic, nie wołają się bezpośrednio, zmiana jednego nie wymaga zmian w drugim, awaria jednego nie koniecznie oznacza zmianę drugiego).

Teraz - jeśli jakiś serwis lub system wchodzi w interakcję z drugim w ten pierwszy sposób (że polegają na sobie) to nie jest i nie może być mikroserwisem, koniec kropka. Mikroserwisy z definicji posługują się tylko tą drugą interakcją.

Sens tego wątku

@Nofenak: Właściwie to muszę Cię przeprosić - zadałeś pytanie o tym jak poprawnie zmodularyzować aplikację; a ja wdałem się w obszerną dyskusję z niedowiarkami czy to w ogóle możliwe.

Odpowiadając na Twoje pytanie, jak poprawnie zmodularyzować aplikacje:

  • Zrób review:
    • Upewnij się czy Twoja aplikacja w ogóle wymaga modularyzacji i czy ma to sens.
    • Odnajdź klasy i funkcje które są ze sobą spójne (cohesive)
    • Odnajdź klasy i funkcje które często zmieniają się razem, np na podstawie historii w kontroli wersji
    • Odnajdź klasy i funkcje które wołają się często siebie nawzajem
    • Ustal jakie są główne funkcjonalności Twojej aplikacji
    • Ustal z jakimi zewnętrznymi systemami Twoja aplikacja się komunikuje (baza, kolejka, widok, system plików, http, etc.)
  • Posiadaj dostateczne umiejętności żeby zmodularyzować aplikacje, w szczególności:
    • Polimorfizm
    • Enkapsulacja
    • Dependency Inversion
  • Przystąp do refaktoru aplikacji:
    • Znajdź moduł który jest najłatwiej wydzielić - być może będzie to widok lub persystencja
    • Nie rób rewolucji, wprowadzaj jedną zmianę na raz - np wydzielenie jednej abstrakcji
    • Wydzielając moduły pamiętaj żeby przekazywać tylko dane biznesowe, a nie szczegóły implementacyjne
edytowany 3x, ostatnio: Riddle
AN
  • Rejestracja:prawie 11 lat
  • Ostatnio:około godziny
  • Postów:973
0

Tylko, że nikt nie twierdził, że serwisy mają być źle napisane i polegają na sobie w taki sposób. To ty wymyśliłeś i teraz kontrargumentujesz tezę, którą tylko ty postawiłeś


Zdalna praca dla Senior Python Developerów --> PW
Riddle
Administrator
  • Rejestracja:ponad 14 lat
  • Ostatnio:36 minut
  • Lokalizacja:Laska, z Polski
  • Postów:10032
0
anonimowy napisał(a):

Tylko, że nikt nie twierdził, że serwisy mają być źle napisane i polegają na sobie w taki sposób. To ty wymyśliłeś i teraz kontrargumentujesz tezę, którą tylko ty postawiłeś

Wszystko zaczęło się od tego że @slsy dał radę pytającemu żeby przekazywać idki pomiędzy mikroserwisami (zamiast obiektów); a ja wtedy powiedziałem że to również jest zależność (taka sama jak przekazywanie obiektów), i lepiej byłoby jednak ich nie przekazywać.

Ty, jak pamiętam, również byłeś w obozie że "idki pomiędzy mikroserwisami są okej".

edytowany 2x, ostatnio: Riddle
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
1
Riddle napisał(a):

To nie jest prawda że "jakiekolwiek zapytanie" to już zależność. Można wysłać zapytanie które nie jest zależnością - jeśli ta komunikacja spełnia pewne kryteria.

No dobra, czyli wg. ciebie jeżeli mam system, który np. śledzi najnowsze memy z kotami w Internecie, w tym celu komunikuje się z Google Search, żeby sobie te koty znaleźć, to nie jest zależny od usługi Google? Jeżeli Google padnie, to podstawowa funkcja tego systemu nie będzie realizowana. Czym dla ciebie jest "zależność"?

markone_dev
  • Rejestracja:około 3 lata
  • Ostatnio:3 dni
  • Postów:809
1

Chyba Riddle chodzi o coś takiego:

Jeśli mam mikroserwis Orders i mikroserwis Shipment to Shipment musi posiadać informację o złożonych zamówieniach.

Przykładowo aby zrealizować przypadek użycia w którym na podstawie rekordu wysyłki, chcemy pobrać szczegóły zamówienia, wysokopoziomowo mogłoby to wyglądać tak (dwa scenariusze):

  1. Współdzielenie id: Usługa Orders wysyła do usługi Shipment informacje o złożonym zamówieniu (jakiś uproszczony model) w tym id zamówienia. Teraz mając w aplikacji listę wysyłek, wybieram jedną z nich aby dostać się do powiązanego z nią zamówienia. Potrzebuję więcej danych niż zostało przesłane w trakcie obsługi zamówienia, więc frontend przekazuje do API Gatewaya id zamówienia pobrane wcześniej z usługi Wysyłka, które leci do usługi Orders i w zwrotce dostaje response ze szczegółowymi danymi zamówienia i wyświetla użytkownikowi.
  2. Brak współdzielenia id: Shipment posiada dokładną kopię zamówienia (a nie uproszczony model) w swojej bazie danych. I przy próbie wyświetlenia szczegółów zamówienia na podstawie rekordu wysyłki, dane pobierane są z usługi Shipment nie Orders.

Co jest lepsze, to zależy i trzeba balansować i wybrać to na co akurat mamy czas, możliwości i pieniądzde.


Programujący korpo architekt chmurowy.
Udzielam konsultacji i szkoleń w obszarze szeroko pojętego cloud computingu (Azure, AWS) i architektury systemów IT. Dla firm i prywatnie.
DevOps to proces nie stanowisko.
edytowany 1x, ostatnio: markone_dev
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
0

Ale to co opisałeś jedynie zmienia typ zależności, ta zależność nie znika. Jak mamy sklep wysyłkowy, który przyjmuje zamówienia jakąś tam drogą, w tych zamówieniach jest co i gdzie ma zostać wysłane, to dział logistyki/wysyłek jest zależny w swoim działaniu od działu sprzedaży przyjmującego te zamówienia. Można dyskutować, czy dział sprzedaży ma wysłać do wysyłek "hej, mamy nowe zamówienie", czy "wyślijcie produkt X na adres Y", ale ta zależność jest wpisana w proces biznesowy przedsiębiorstwa. Jeżeli piszemy system, który ma ten proces jakoś tam usprawniać (np. eliminując gubienie papierków przez gońca), to zależność nadal w nim będzie.
Oczywiście można tak zaprojektować system, żeby padnięcie serwisu od sprzedaży nie powodowało z automatu natychmiastowej przerwy w działaniu logistyki, ale to nie usuwa zależności jako takiej, bo wciąż jak przestaniemy przyjmować zamówienia, to po jakimś czasie logistyka przestanie mieć co robić, a cały proces się zatrzyma.

markone_dev
  • Rejestracja:około 3 lata
  • Ostatnio:3 dni
  • Postów:809
0

Ale to co opisałeś jedynie zmienia typ zależności, ta zależność nie znika.

Ja tylko próbuję zgadnąć co autor (Riddle) ma na myśli. Zależność będzie zawsze występować bo ona tam po prostu jest. Jeśli popatrzeć z punktu widzenia biznesowego to dział zajmujący się wysyłką musi posiadać wiedzę o zamówieniach no bo jak inaczej by firma miała działać. Przekładając to na język techniczny to usługa Shipment musi mieć wiedzę o zamówieniach z usługi Orders. Kwestia tego jak to zaimplementujemy tak by te usługi od siebie były jak najbardziej niezależne, czyli osobne zespoły, modele dziedzinowe, duplikacja danych, komunikacja asynchroniczna za pomocą kolejek wersjonowanie komunikatów, itd.

Inna kwestia czy 95% platform e-commerce spełnia wymagania biznesowe uzasadniające taki barokowy design.


Programujący korpo architekt chmurowy.
Udzielam konsultacji i szkoleń w obszarze szeroko pojętego cloud computingu (Azure, AWS) i architektury systemów IT. Dla firm i prywatnie.
DevOps to proces nie stanowisko.
edytowany 3x, ostatnio: markone_dev
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
0
markone_dev napisał(a):

Ja tylko próbuję zgadnąć co autor (Riddle) ma na myśli.

No trochę jak Żywot Briana i interpretowanie słów proroka, które muszą mieć sens, bo przecież zostały wypowiedziane przez proroka.

Zależność będzie zawsze występować bo ona tam po prostu jest. Jeśli popatrzeć z punktu widzenia biznesowego to dział zajmujący się wysyłką musi posiadać wiedzę o zamówieniach no bo jak inaczej by firma miała działać. Przekładając to na język techniczny to usługa Shipment musi mieć wiedzę o zamówieniach z usługi Orders. Kwestia tego jak to zaimplementujemy tak by te usługi od siebie były jak najbardziej niezależne, czyli osobne zespoły, modele dziedzinowe, duplikacja danych, komunikacja asynchroniczna za pomocą kolejek wersjonowanie komunikatów, itd.

Trochę nie ma o czym dyskutować, bo właściwie piszemy to samo.

Inna kwestia czy 95% platform e-commerce spełnia wymagania biznesowe uzasadniające taki barokowy design.

To osobna kwestia, dałem to jako przykład, który każdy jest w stanie zrozumieć. Natomiast przy jako tako ogarniętym obszarze DevOps, z mikrousługami da się żyć w przyjaźni. Z mojego punktu widzenia np. bardzo duże korzyści wynikają z tego, że:

  • Mam odpowiedzialności pocięte na małe kawałki i jeżeli pilnuję kontenerów, to splątania "wewnątrz" każdego z nich przestają być istotne, bo w najgorszym razie ktoś taki kontener weźmie i napisze od zera w sensownym czasie.
  • Można próbować nowych technologii, podejść, języków programowania, bo znowu, ryzyko, że takie eksperymenty doprowadzą ro ruiny cały system jest zerowe
  • Mam dużo prostsze testowanie
  • Mam jasne i widoczne zależności pomiędzy usługami, a w monolicie, zawsze przemknie jakieś "na szybko sięgnę do danych z innego modułu"

Oczywiście warunkiem jest, że infrastruktura projektu pozwala na utworzenie szkieletu nowej usługi powiedzmy w godzinę, może 2. Mam na myśli utworzenie nowego repozytorium (albo katalogu w monorepo), włączenie tego repo w CI/CD, podpięcie narzędzi analizy statycznej i automatyczny deploy.

No i jak pójdziesz do biznesu w postaci Jasia Szaraczka z pytaniem jaki ruch przewiduje na tej platformie b2c, to z automatu ci powie, że będzie to milion zamówień dziennie.

AN
  • Rejestracja:prawie 11 lat
  • Ostatnio:około godziny
  • Postów:973
0
piotrpo napisał(a):
Riddle napisał(a):

To nie jest prawda że "jakiekolwiek zapytanie" to już zależność. Można wysłać zapytanie które nie jest zależnością - jeśli ta komunikacja spełnia pewne kryteria.

No dobra, czyli wg. ciebie jeżeli mam system, który np. śledzi najnowsze memy z kotami w Internecie, w tym celu komunikuje się z Google Search, żeby sobie te koty znaleźć, to nie jest zależny od usługi Google? Jeżeli Google padnie, to podstawowa funkcja tego systemu nie będzie realizowana. Czym dla ciebie jest "zależność"?

@piotrpo: Zależy. Jeśli przy okazji bierzesz sobie zapisujesz sobie id obrazków z Google (żeby wiedzieć np. które już pobrałeś) to cytując @Riddle

[Riddle napisał(a)]

Jeśli masz dwie aplikacje które gadają po HTTP/REST, i wymieniają miedzy sobą id, to te dwie aplikacje nie są mikroserwisami.


Zdalna praca dla Senior Python Developerów --> PW
NO
  • Rejestracja:ponad 2 lata
  • Ostatnio:11 dni
  • Postów:135
0

@Riddle: Tak, chodziło mi tylko o modularyzację a nie o to czy warto wdrażać mikroserwisy, ale fajnie, że tyle osób się wypowiedziało. Póki co najbardziej do mnie przemawia sposób z patrzeniem na to, żeby awaria jednej usługi/modułu nie powodowała awarii drugiej.

piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
0

@Nofenak: Nie dotyczy wyłącznie mikroserwisów, ale fajnie myśleć o architekturze w takich kategoriach https://docs.aws.amazon.com/wellarchitected/latest/framework/the-pillars-of-the-framework.html

Kopiuj
Operational excellence
Security
Reliability
Performance efficiency
Cost optimization
Sustainability
markone_dev
  • Rejestracja:około 3 lata
  • Ostatnio:3 dni
  • Postów:809
2

@Nofenak:
Musisz się zdecydować bo zaczynasz od:

chodziło mi tylko o modularyzację a nie o to czy warto wdrażać mikroserwisy,

Po czym piszesz:

żeby awaria jednej usługi/modułu nie powodowała awarii drugiej.

Jak masz monolit (nawet modularny) to awaria jednego modułu np. memory leak w połączeniu do bazy danych położy całą aplikację, ponieważ moduły w modularnym monolicie są od siebie odseparowane, ale na poziomie kodu, nie infrastruktury. Jak jeden moduł żeżre całą pamięć serwera to serwer padnie i cała aplikacja też.

Jak twoim wymaganiem jest uniezależnić wpływ awarii jednego modułu na drugi, to niestety ale pchasz się w architekturę rozproszoną (nie od razu mikroserwisy). Możesz mieć przecież wydzielony z aplikacji serwis do np konwertowania dużych plików po to by nie zamulał głównej aplikacji i niezależnie go skalować, wdrażać itd.


Programujący korpo architekt chmurowy.
Udzielam konsultacji i szkoleń w obszarze szeroko pojętego cloud computingu (Azure, AWS) i architektury systemów IT. Dla firm i prywatnie.
DevOps to proces nie stanowisko.
edytowany 1x, ostatnio: markone_dev
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
2

Niezawodność, to trochę szerszy temat, bo przecież oprócz tego kodu może się zdarzyć, że:

  • walnie serwer
  • walnie kabelek do datacenter
  • ktoś zrąbie dns'y i cała chmura walnie
  • wygaśnie jakiś certyfikat gdzieś tam

W mikroserwisach, ta mityczna niezawodność jest zwykle raczej skutkiem ubocznym, niż celem samym w sobie. Raczej ciężko się spodziewać wymagania "sklep ma pokazywać listę towarów, nawet jeżeli nie da się ich dodać do koszyka". Można oczywiście zdefiniować jakieś krytyczne funkcje systemu i sprawić, że będą działać nawet jak reszta padnie, albo testować chaos monkey na produkcji, ale to znowu raczej zabawa dla bogatych.

DM
Niezawodność czy decoupling? Opierając się na Twoim przykładzie - nawet jeżeli sklep tylko pokazuje listę towarów, to już jest tutaj wartość biznesowa taka jak np. indeksowanie google, czy użytkownik przeglądający te towary który potem dostanie info że jest 'czasowa' awaria z koszykiem(lub tylko przejrzy i wróci później). W pub/sub serwis A i B zrobią swoją pracę, pomimo tego, że serwis C leży. C później nadgoni. To jest bardzo podobny problem jak w kontenerze Dockera z wieloma procesami(anty wzorzec) - główny pada i kontener pada bez względu na inne(nie subprocesy)
piotrpo
Ale ja się zgadzam (i nawet piszę), że niezawodność jest skutkiem ubocznym "rozplątania". Można też się zabezpieczyć przed niektórymi typami awarii. Wrzucenie stateless kontenerów w klaster k8s daje np. jakąś tam nadmiarowość infrastruktury. Efemeryczność kontenerów też podnosi odporność na błędy. Ale jeżeli ta niezawodność jest bardzo ważna, to musi zostać zaplanowana.
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:dzień
  • Lokalizacja:Wrocław
3
anonimowy napisał(a):

Dlaczego oceniasz wszystko na podstawie słabych firm, w których pracowałeś? Ja nie spotkałem się jeszcze z kimś kto nie rozumie TDD.

A zatem nie masz konta na 4p, a więc i nie mogłeś napisać tego posta. :)

W 90% przypadków ludzie mówią, że mają TDD, gdy po mają jakieś testy w projekcie. (I to jest sukces, bo wciąż istnieją ludzie, którym "manager zabrania" pisać testy.) Dalsze 9% przypadków to ludzie, którzy przez TDD rozumieją "pisanie testów przed implementacją".
Pozostały 1% składa się z: 0,99% ludzie, którzy piszą testy przed implementacją, ale wiedzą że to nie jest TDD oraz 0,01%, którzy faktycznie TDD stosują zawsze. Na szczęście mało kiedy wytwarzają coś przydatnego, więc rzadko się ich widzi.

Krolik napisał(a):

Dość sceptycznie podchodzę do kwestii skalowania - monolityczna aplikacja może się dobrze skalować tak samo jak mikroserwis - serio nieużywanego kodu po prostu można nie ładować do pamięci, a naprawdę kilka, kilkadziesiąt MB więcej kodu na dysku to obecnie nie jest problem. Bardziej patrzyłbym przez pryzmat wygody konfiguracji, zwłaszcza jeśli mamy pewne elementy bezstanowe. Elementy bezstanowe będzie skalować łatwiej, więc może warto je oddzielić od tych stanowych.

Gdyby problem z monolitami polegał na tym, że zajmują kilkadziesiąt MB na dysku, to nie wiem, czy ktoś by w ogóle wpadł na tworzenie mikroserwisów.
Ale nawet te marnowane gigabajty dysku nie są problemem, problemem jest RAM. Coś, co potrzebuje 128GB, żeby się w ogóle odpalić nie skaluje się tak dobrze jak mikroserwis. A jak do tego używa RDBMSa, to skalowania prawie nie ma.

piotrpo napisał(a):

Tak mi się nasunęło na myśl podczas czytania tej dyskusji, że właściwie nie istnieje jakaś ogólna, przyjęta definicja architektury mikroserwisowej, więc równie dobrze wszyscy mogą mieć rację. To z czym się zetknąłem, to "zbiór małych, luźno powiązanych usług, o dobrze zdefiniowanych API".

No i trzymajac się tej definicji możemy zrobić kalkulator na mikroserwisach, w którym każde działanie będzie realizowane przez oddzielny mikroserwis. ;)

Natomiast jeżeli patrzymy na to nieco szerzej, to jest to wyniesienie ogólnie znanych zasad SOLID do poziomu osobnych usług.

No to chyba doskonale wyjaśnia cały problem. Ponieważ prawie nikt nie ogarnia SOLIDa, to i na ogarnięcie mikroserwisów nie ma szans. :)

Nie ma też jasnej odpowiedzi na pytanie, czy "mikroserwisy są lepsze od monolitu, czy odwrotnie".

Tak naprawdę, to taka odpowiedź istnieje, tylko nie każdy do niej dojrzał.

markone_dev napisał(a):

Zależność będzie zawsze występować bo ona tam po prostu jest.

Zależność będzie, jeśli ją wprowadzimy i utrzymamy. Biznes nie każe nam komunikować się idkami. :)
Ogólnie, to Riddle chyba ma coś na myśli, tylko nie umie tego precyzyjnie wyjaśnić.
Ja tam np. nie wiem, po co jakieś ID maja latać między mikroserwisami, skoro w mikroserwisie B taki ID z A jest tylko losową liczbą bez żadnego znaczenia. Co sobie B ma z tym zrobić? W jego bazie takiego rekordu przecież nie ma.

piotrpo napisał(a):

W mikroserwisach, ta mityczna niezawodność jest zwykle raczej skutkiem ubocznym, niż celem samym w sobie.

Nie szukasz czasem pracy? U nas na pewno by zatrudnili kogoś, komu niezawodność wychodzi przypadkiem, jako skutek całkiem innych działań. :P
Bo tak ogólnie to cała niezawodność, to ogromny temat, zahaczający o takie tematy jak redundancja i georeplikacja, a takich rzeczy nie da się zrobić przypadkiem.


Po dopracowaniu rozwiązania każdy będzie mógł założyć własny drzewiasty wątek.
markone_dev
  • Rejestracja:około 3 lata
  • Ostatnio:3 dni
  • Postów:809
1

@somekind:

Zależność będzie, jeśli ją wprowadzimy i utrzymamy. Biznes nie każe nam komunikować się idkami. :)

Tu chodziło mi o zależność biznesową nie techniczną :P Więc takiej komunikacji korzystamy z takich bytów jak wniosek/prośba, itd, które powinny być częścią API systemu.


Programujący korpo architekt chmurowy.
Udzielam konsultacji i szkoleń w obszarze szeroko pojętego cloud computingu (Azure, AWS) i architektury systemów IT. Dla firm i prywatnie.
DevOps to proces nie stanowisko.
edytowany 1x, ostatnio: markone_dev
AN
  • Rejestracja:prawie 11 lat
  • Ostatnio:około godziny
  • Postów:973
0

W takim razie w jaki sposób system płatności może poinformować inny system, że dana paczka została opłacona skoro nie może mieć id/uuid danej paczki?


Zdalna praca dla Senior Python Developerów --> PW
Zobacz pozostałe 5 komentarzy
AN
id to id, gdzie napisałem, że id to nie jest identyfikator biznesowy?
somekind
Nie mówię, że Ty tak napisałeś, po prostu chciałem uściślić o jakie ID mi chodziło, bo sam termin "ID" jest dość ogólny i nieprecyzyjny. Np. Riddle coś o tym napisał, i do tej pory nie wiadomo, o co mu dokładnie chodziło.
AN
A co w przypadku gdy nie potrzebujesz biznesowego ID a technicznie nadal musisz zidentyfikować obiekt?
somekind
Nie umiem sobie takiego przypadku wyobrazić. Jeśli coś nie potrzebuje biznesowego ID to może być co najwyżej jakimś głębokim szczegółem implementacji nigdy nie opuszczającym swojego modułu.
AN
Powiedzmy np. użytkownik. Owszem w bazie ma swoje ID ale nigdzie nie musimy pokazywać tego użytkownikowi
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
0
somekind napisał(a):

Pozostały 1% składa się z: 0,99% ludzie, którzy piszą testy przed implementacją, ale wiedzą że to nie jest TDD oraz 0,01%, którzy faktycznie TDD stosują zawsze. Na szczęście mało kiedy wytwarzają coś przydatnego, więc rzadko się ich widzi.

Oj, podpada pod obrazę uczuć religijnych :)

piotrpo napisał(a):

Tak mi się nasunęło na myśl podczas czytania tej dyskusji, że właściwie nie istnieje jakaś ogólna, przyjęta definicja architektury mikroserwisowej, więc równie dobrze wszyscy mogą mieć rację. To z czym się zetknąłem, to "zbiór małych, luźno powiązanych usług, o dobrze zdefiniowanych API".

No i trzymajac się tej definicji możemy zrobić kalkulator na mikroserwisach, w którym każde działanie będzie realizowane przez oddzielny mikroserwis. ;)

Da się, pytanie po co?

Natomiast jeżeli patrzymy na to nieco szerzej, to jest to wyniesienie ogólnie znanych zasad SOLID do poziomu osobnych usług.

No to chyba doskonale wyjaśnia cały problem. Ponieważ prawie nikt nie ogarnia SOLIDa, to i na ogarnięcie mikroserwisów nie ma szans. :)

Wystarczy użyć Basic'a, że pozwolę sobie na Innej Joke.

Nie ma też jasnej odpowiedzi na pytanie, czy "mikroserwisy są lepsze od monolitu, czy odwrotnie".

Tak naprawdę, to taka odpowiedź istnieje, tylko nie każdy do niej dojrzał.

No trochę tak, chociaż w niektórych przypadkach koszt wystartowania i utrzymania projektu mikroserwisowego przeważy korzyści.

piotrpo napisał(a):

W mikroserwisach, ta mityczna niezawodność jest zwykle raczej skutkiem ubocznym, niż celem samym w sobie.

Nie szukasz czasem pracy? U nas na pewno by zatrudnili kogoś, komu niezawodność wychodzi przypadkiem, jako skutek całkiem innych działań. :P
Bo tak ogólnie to cała niezawodność, to ogromny temat, zahaczający o takie tematy jak redundancja i georeplikacja, a takich rzeczy nie da się zrobić przypadkiem.

Oczywiście, opisałem tę moją mętną myśl w komentarzu wyżej:

Ale ja się zgadzam (i nawet piszę), że niezawodność jest skutkiem ubocznym "rozplątania". Można też się zabezpieczyć przed niektórymi typami awarii. Wrzucenie stateless kontenerów w klaster k8s daje np. jakąś tam nadmiarowość infrastruktury. Efemeryczność kontenerów też podnosi odporność na błędy. Ale jeżeli ta niezawodność jest bardzo ważna, to musi zostać zaplanowana.

Ale decydując się na "wrzucimy to jako kilka usług do klastra k8s" z automatu dostajemy np. redundancję na poziomie sprzętu, bo będzie to uruchamiane na kilku maszynach zamiast jednej, Wszystko co przekracza ten poziom wymaga już jakiegoś aktywnego działania, np. zadbania o to, żeby instancje tej samej usługi działały jednocześnie w różnych availability zones.

edytowany 1x, ostatnio: piotrpo
Drzewiec
  • Rejestracja:około 6 lat
  • Ostatnio:około 14 godzin
  • Postów:115
0

Zgadzam się w pełni z tym, że ludzie mają często problem z nazewnictwem i używają terminów związanych z architekturą jako buzz words. Najlepiej po prostu się tym nie przejmować i samemu weryfikować, instruować, uświadamiać, itd. Przecież w prawdziwym świecie nikt nie wyjdzie na środek open space i nie krzyknie TO NIE SĄ MIKROSERWISY, ROBIMY NATYCHMIASTOWY REFACTOR! Nikt też nie powie, że "mamy prawie mikroserwisy", albo "mamy monolit", jak mikroserwisy są nie do końca dobrze zrobione - powie po prostu, "mamy mikroserwisy". To po prostu rozjazd między standardami, a rzeczywistością, który zawsze w pewnym stopniu zachodzi.

ZN
znowutosamo
A to nie jest wtedy kula błota? A ludzie z samej życzliwości bądź / i strachu nie mówią o tym głośno?
piotrpo
@znowutosamo: Jak z życzliwości/strachu ludzie nie mówią o problemach, to jest to ciepły ...dołek, a nie projekt. Pozostaje miły tak długo, aż ktoś przyjdzie i się zorientuje, że parę baniek poszło na nic.
ZN
znowutosamo
no wydaje mi się, że to w jakimś stopniu rozjazd między standardami a rzeczywistością ;)
piotrpo
To jest rzeczywistość. Jeżeli przebywanie w strefie komfortu jest ważniejsze od zrobienia porządnej roboty, to prędzej czy później ta strefa komfortu znika. Powodem zniknięcia może być drący ryja biznes, zamknięcie projektu, zamknięcie firmy. Zależy od organizacji jak szybko reaguje. Niektóre mogą reagować i 20 lat :)
ZN
znowutosamo
no i wtedy mamy: ludzie z samej życzliwości bądź / i strachu nie mówią o tym głośno. Typowe, nie? Generalnie na samym końcu to nie wykonawcy podejmują decyzje więc narzekanie, aby zwrócić uwagę na problem za bardzo się nie sprzedaje. Ze względu, że firmy lubią ogień. To lepiej na to czekać aż pojawi się pożar, wtedy przynajmniej są większe szanse na awans i bycie dostrzeżonym.
piotrpo
  • Rejestracja:ponad 7 lat
  • Ostatnio:około godziny
  • Postów:3277
1

@Drzewiec: Celem projektu nigdy nie powinno być zrobienie czegoś jako mikroserwisy, monolit, w jakiejś konkretnej technologii. Celem projektu jest spełnienie odpowiednich wymagań funkcjonalnych, oraz niefunkcjonalnych. Projekt nie powinien w żadnym momencie mieć w wymaganiach "musi być mikroserwis", bo to nie ma znaczenia. Taka decyzja może (i powinna być) wynikać z wymagań niefunkcjonalnych jak "musimy być gotowi do obsługi skokowo wysokiego ruchu w ciągu doby", ale klienta nie obchodzi (a w każdym razie nie powinno obchodzić) co jest w bebechach systemu i w jaki sposób realizuje on zamówioną funkcjonalność.

ZN
znowutosamo
są pewne wyjątki np. aby użyć technologii która zwabi inwestorów, bądź która ułatwi pozyskanie dofinansowania
piotrpo
Rozsądnych inwestorów nie obchodzi jak zrobisz to co obiecujesz, tylko czy masz szansę rozwiązać problem, którego nie rozwiązał nikt inny i ile rynek będzie chciał ci zapłacić za rozwiązanie tego problemu. Pomijam utrzymywane za publiczne pieniądze inkubatory, dotacje na rozwój i resztę podobnych patologii, bo one nie mają wiele wspólnego z rozwojem oprogramowania.
B2
  • Rejestracja:około 2 lata
  • Ostatnio:dzień
  • Postów:71
3

@Nofenak
Jeśli autorze wątku nadal jesteś tu z nami i się zastanawiasz co tu się odwaliło, to chciałbym cię tylko uspokoić, że to jest normalne w tej branży. Nawet gdy będziesz miał 20 lat doświadczenia w zawodzie, to zawsze znajdzie się ktoś, kto przyjdzie i powie że przez ostatnie 10 lat robiłeś coś źle i że to nie było "prawdziwe". To tylko dowodzi temu, że programowanie ma dużo wspólnego ze sztuką, czasami więcej niż z naukami ścisłymi.

KR
Moderator
  • Rejestracja:prawie 21 lat
  • Ostatnio:2 miesiące
  • Postów:2964
0

Coś, co potrzebuje 128GB, żeby się w ogóle odpalić nie skaluje się tak dobrze jak mikroserwis

A na to to jest prosta rada: nie pisać oprogramowania które potrzebuje 128 GB RAMu aby się odpalić. Z nielicznymi wyjątkami że ktoś liczy prognozę pogody na 10 dni dla całego kontynentu, symuluje opływ powietrza wokół samolotu czy trenuje gpt-5 to nie widzę potrzeby używać tyle RAMu. Po prostu jak ktoś ma taki problem to problemem nie jest monolit a źle napisana aplikacja.

Jeśli już coś to mikroserwisy zużywają więcej RAMu sumarycznie bo kawałki monolitu po rozbiciu na N mikroserwisów nie zużywają N razy mniej RAMu. Funkcjonalność sumarycznie musisz mieć taką samą, ale pewne elementy się duplikują. I dochodzi dodatkowy kod związany z komunikacją między serwisami.

Zobacz pozostałe 17 komentarzy
KR
Przykładowo - masz monolit który umie robić panoramy oraz kompresować filmy. Do obu zadań potrzeba multum RAMu. Rozdzielenie go na dwa mikroserwisy specjalizujące się osobno w panoramach i w filmach ani trochę nie zmniejszy zapotrzebowania na RAM całego systemu. Co najwyżej ten sam RAM będziesz musiał podzielić pomiędzy więcej maszyn, ale wyjdzie na jedno (zakładając że przetwarzasz tyle samo multimediów w jednostce czasu).
loza_prowizoryczna
Jak jesteś Googlem/Applem i robisz takie przetwarzanie na masową skalę - nie jestem i nie na masową ale powiedzmy że jest to w obrębie moich zainteresowań. Do obu zadań potrzeba multum RAMu - trzeba pamięci ale niekoniecznie musi to być RAM, dlatego podniosłem temat memory tieringu. RAM był oczywisty do czasu adwentu tanich SSD bo nawet macierze RAID były rzędy razy wolniejsze i nie miało to sensu. Bo najpierw pisaliśmy o korporacyjnych apkach serwerowych - może coś mnie ominęło ale to brzmiało tak nie pisać oprogramowania które potrzebuje 128 GB RAMu aby się ...
loza_prowizoryczna
Podsumowując: Ja wychodzę z założenia że rozmiar pamięci nie ma aż tak dużego znaczenia jeśli nie stanowi on problemu w działaniu i wdrożeniu aplikacji. Mikroserwis rozdzielający taski na klastrze GPU lecącym na współdzielonym obszarze pamięci który jest na uwarstwionym kontenerze (czyli za cholerę nie dojdziesz czy ciągniesz akurat dane z RAID, SSD, RAMu chyba że liczysz opóźnienia) nie jest źle napisany. Tak samo nie uważam za zły taki sam mikroserwis generujący korpobełkot jeśli zaprojektowany pod coś takiego (i działa na wewnętrznej infrastrukturze).
KR
Kontekst dyskusji był jednak inny. Teza była taka, żeby rozdzielać na mikroserwisy, bo wtedy każdy zajmie mniej pamięci i łatwiej skalować je niezależnie. Domyślnie: bo monolit jest wielki, ciężki i wcina 128 GB RAMu tylko po to aby się odpalić. Nigdzie nie kwestionowałem pisania aplikacji które faktycznie wymagają tyle zasobów bo fizyki nie przeskoczą. Pisałem o apkach wcinających multum zasobów bo są bardzo słabo napisane i zwalanie tego na monolityczna architekturę.
loza_prowizoryczna
W takim razie ok. Tylko nawet wtedy łatwiej skalować je niezależnie. jest w mocy bo jak rozbijesz taką kobyłę na izolowane środowiska/procesy to mimo że sumarycznie zajmą więcej to zawsze masz korzyść z tego że możesz ubijać/podnosić te instancje na żądanie nie zwracając zbytnio uwagi na to jak źle są napisane bo ich wpływ na stabilność całości jest ograniczony. Jeden źle napisany moduł/serwis nie przewróci ci systemu tylko zwróci uwagę na problem i przez pewien czas można po prostu ten problem zamaskować dorzucając więcej instancji. To jest duża zaleta.
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:dzień
  • Lokalizacja:Wrocław
0
Krolik napisał(a):

Coś, co potrzebuje 128GB, żeby się w ogóle odpalić nie skaluje się tak dobrze jak mikroserwis

A na to to jest prosta rada: nie pisać oprogramowania które potrzebuje 128 GB RAMu aby się odpalić.

Wiesz, tylko nikt nie pisze z założeniem, że tyle pamięci zajmie. Dzięki fantastycznej architekturze monolitycznej tak po prostu wychodzi, jeśli się chce upchać wszystkie ficzery średniej wielkości firmy w jednym systemie. Niektórzy pewnie są nawet dumni ze zrobienia czegoś takiego.

Jeśli już coś to mikroserwisy zużywają więcej RAMu sumarycznie bo kawałki monolitu po rozbiciu na N mikroserwisów nie zużywają N razy mniej RAMu.
Funkcjonalność sumarycznie musisz mieć taką samą, ale pewne elementy się duplikują. I dochodzi dodatkowy kod związany z komunikacją między serwisami.

Ale z drugiej strony, to mniejsze aplikacje dają mniejsze szanse na dziwne zależności, które zapobiegają prawidłowemu zwalnianiu pamięci, latwiej też wykrywać marnowane zasoby i je optymalizować. No i jak słusznie zauważył @mstl w komentarzu, można to sensownie skalować.
Póki co mikroserwisowa wersja naszego systemu nie zajmuje tyle, co monolit.

Poza tym to tak nie działa, że rozbija się monolit na mikroserwisy.


Po dopracowaniu rozwiązania każdy będzie mógł założyć własny drzewiasty wątek.
markone_dev
  • Rejestracja:około 3 lata
  • Ostatnio:3 dni
  • Postów:809
1

@somekind:

Poza tym to tak nie działa, że rozbija się monolit na mikroserwisy.

Nie działa bo? Uczestniczyłem w takich projektach, więc nie bardzo rozumiem co chcesz przez to powiedzieć.


Programujący korpo architekt chmurowy.
Udzielam konsultacji i szkoleń w obszarze szeroko pojętego cloud computingu (Azure, AWS) i architektury systemów IT. Dla firm i prywatnie.
DevOps to proces nie stanowisko.
KR
Moderator
  • Rejestracja:prawie 21 lat
  • Ostatnio:2 miesiące
  • Postów:2964
1

Zapewne to że oprócz rozbicia na mikroserwisy zoptymalizowali to i tamto i teraz sumarycznie działa lepiej.

somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:dzień
  • Lokalizacja:Wrocław
2

Bo nie chodzi o to, że bierzemy kod, jakoś dzielimy na kawałki i oddzielnie wdrażamy. Ten soft trzeba napisać od nowa, od początku uwzględniając inną architekturę.


Po dopracowaniu rozwiązania każdy będzie mógł założyć własny drzewiasty wątek.
markone_dev
  • Rejestracja:około 3 lata
  • Ostatnio:3 dni
  • Postów:809
1

A no to wiadomo.


Programujący korpo architekt chmurowy.
Udzielam konsultacji i szkoleń w obszarze szeroko pojętego cloud computingu (Azure, AWS) i architektury systemów IT. Dla firm i prywatnie.
DevOps to proces nie stanowisko.
somekind
Moderator
  • Rejestracja:około 17 lat
  • Ostatnio:dzień
  • Lokalizacja:Wrocław
1
markone_dev napisał(a):

A no to wiadomo.

No ja właśnie nie wiem, czy to takie wiadome. Mam wrażenie, że wielu ludzi wypieprza się na przerabianiu monolitu na mikroserwisy jak krowa na łyżwach.


Po dopracowaniu rozwiązania każdy będzie mógł założyć własny drzewiasty wątek.
edytowany 1x, ostatnio: somekind
loza_prowizoryczna
  • Rejestracja:ponad 2 lata
  • Ostatnio:około 20 godzin
  • Postów:1583
0

A tak z innej beczki - łatwiej jest poddać audytowi pod kątem bezpieczeństwa archi oparte o mikroserwisy czy monolityczną kobyłę?


Przetrzyma wszystko
Kliknij, aby dodać treść...

Pomoc 1.18.8

Typografia

Edytor obsługuje składnie Markdown, w której pojedynczy akcent *kursywa* oraz _kursywa_ to pochylenie. Z kolei podwójny akcent **pogrubienie** oraz __pogrubienie__ to pogrubienie. Dodanie znaczników ~~strike~~ to przekreślenie.

Możesz dodać formatowanie komendami , , oraz .

Ponieważ dekoracja podkreślenia jest przeznaczona na linki, markdown nie zawiera specjalnej składni dla podkreślenia. Dlatego by dodać podkreślenie, użyj <u>underline</u>.

Komendy formatujące reagują na skróty klawiszowe: Ctrl+B, Ctrl+I, Ctrl+U oraz Ctrl+S.

Linki

By dodać link w edytorze użyj komendy lub użyj składni [title](link). URL umieszczony w linku lub nawet URL umieszczony bezpośrednio w tekście będzie aktywny i klikalny.

Jeżeli chcesz, możesz samodzielnie dodać link: <a href="link">title</a>.

Wewnętrzne odnośniki

Możesz umieścić odnośnik do wewnętrznej podstrony, używając następującej składni: [[Delphi/Kompendium]] lub [[Delphi/Kompendium|kliknij, aby przejść do kompendium]]. Odnośniki mogą prowadzić do Forum 4programmers.net lub np. do Kompendium.

Wspomnienia użytkowników

By wspomnieć użytkownika forum, wpisz w formularzu znak @. Zobaczysz okienko samouzupełniające nazwy użytkowników. Samouzupełnienie dobierze odpowiedni format wspomnienia, zależnie od tego czy w nazwie użytkownika znajduje się spacja.

Znaczniki HTML

Dozwolone jest używanie niektórych znaczników HTML: <a>, <b>, <i>, <kbd>, <del>, <strong>, <dfn>, <pre>, <blockquote>, <hr/>, <sub>, <sup> oraz <img/>.

Skróty klawiszowe

Dodaj kombinację klawiszy komendą notacji klawiszy lub skrótem klawiszowym Alt+K.

Reprezentuj kombinacje klawiszowe używając taga <kbd>. Oddziel od siebie klawisze znakiem plus, np <kbd>Alt+Tab</kbd>.

Indeks górny oraz dolny

Przykład: wpisując H<sub>2</sub>O i m<sup>2</sup> otrzymasz: H2O i m2.

Składnia Tex

By precyzyjnie wyrazić działanie matematyczne, użyj składni Tex.

<tex>arcctg(x) = argtan(\frac{1}{x}) = arcsin(\frac{1}{\sqrt{1+x^2}})</tex>

Kod źródłowy

Krótkie fragmenty kodu

Wszelkie jednolinijkowe instrukcje języka programowania powinny być zawarte pomiędzy obróconymi apostrofami: `kod instrukcji` lub ``console.log(`string`);``.

Kod wielolinijkowy

Dodaj fragment kodu komendą . Fragmenty kodu zajmujące całą lub więcej linijek powinny być umieszczone w wielolinijkowym fragmencie kodu. Znaczniki ``` lub ~~~ umożliwiają kolorowanie różnych języków programowania. Możemy nadać nazwę języka programowania używając auto-uzupełnienia, kod został pokolorowany używając konkretnych ustawień kolorowania składni:

```javascript
document.write('Hello World');
```

Możesz zaznaczyć również już wklejony kod w edytorze, i użyć komendy  by zamienić go w kod. Użyj kombinacji Ctrl+`, by dodać fragment kodu bez oznaczników języka.

Tabelki

Dodaj przykładową tabelkę używając komendy . Przykładowa tabelka składa się z dwóch kolumn, nagłówka i jednego wiersza.

Wygeneruj tabelkę na podstawie szablonu. Oddziel komórki separatorem ; lub |, a następnie zaznacz szablonu.

nazwisko;dziedzina;odkrycie
Pitagoras;mathematics;Pythagorean Theorem
Albert Einstein;physics;General Relativity
Marie Curie, Pierre Curie;chemistry;Radium, Polonium

Użyj komendy by zamienić zaznaczony szablon na tabelkę Markdown.

Lista uporządkowana i nieuporządkowana

Możliwe jest tworzenie listy numerowanych oraz wypunktowanych. Wystarczy, że pierwszym znakiem linii będzie * lub - dla listy nieuporządkowanej oraz 1. dla listy uporządkowanej.

Użyj komendy by dodać listę uporządkowaną.

1. Lista numerowana
2. Lista numerowana

Użyj komendy by dodać listę nieuporządkowaną.

* Lista wypunktowana
* Lista wypunktowana
** Lista wypunktowana (drugi poziom)

Składnia Markdown

Edytor obsługuje składnię Markdown, która składa się ze znaków specjalnych. Dostępne komendy, jak formatowanie , dodanie tabelki lub fragmentu kodu są w pewnym sensie świadome otaczającej jej składni, i postarają się unikać uszkodzenia jej.

Dla przykładu, używając tylko dostępnych komend, nie możemy dodać formatowania pogrubienia do kodu wielolinijkowego, albo dodać listy do tabelki - mogłoby to doprowadzić do uszkodzenia składni.

W pewnych odosobnionych przypadkach brak nowej linii przed elementami markdown również mógłby uszkodzić składnie, dlatego edytor dodaje brakujące nowe linie. Dla przykładu, dodanie formatowania pochylenia zaraz po tabelce, mogłoby zostać błędne zinterpretowane, więc edytor doda oddzielającą nową linię pomiędzy tabelką, a pochyleniem.

Skróty klawiszowe

Skróty formatujące, kiedy w edytorze znajduje się pojedynczy kursor, wstawiają sformatowany tekst przykładowy. Jeśli w edytorze znajduje się zaznaczenie (słowo, linijka, paragraf), wtedy zaznaczenie zostaje sformatowane.

  • Ctrl+B - dodaj pogrubienie lub pogrub zaznaczenie
  • Ctrl+I - dodaj pochylenie lub pochyl zaznaczenie
  • Ctrl+U - dodaj podkreślenie lub podkreśl zaznaczenie
  • Ctrl+S - dodaj przekreślenie lub przekreśl zaznaczenie

Notacja Klawiszy

  • Alt+K - dodaj notację klawiszy

Fragment kodu bez oznacznika

  • Alt+C - dodaj pusty fragment kodu

Skróty operujące na kodzie i linijkach:

  • Alt+L - zaznaczenie całej linii
  • Alt+, Alt+ - przeniesienie linijki w której znajduje się kursor w górę/dół.
  • Tab/⌘+] - dodaj wcięcie (wcięcie w prawo)
  • Shit+Tab/⌘+[ - usunięcie wcięcia (wycięcie w lewo)

Dodawanie postów:

  • Ctrl+Enter - dodaj post
  • ⌘+Enter - dodaj post (MacOS)