Pytanie o serwisy infrastrukturalne, modelowanie obiektu i bezstanowość

Pytanie o serwisy infrastrukturalne, modelowanie obiektu i bezstanowość
1

Od kilku lat programuję w javie, ostatnio pooglądałem trochę konferencji, poczytałem tematów, postanowiłem zmienić podejście. Mam kilka pytań:

  1. Załóżmy, że mamy moduł "Weather", który pozwala nam sprawdzić pogodę dla współrzędnych geograficznych. Mamy jakąś fasadę, która wywołuję metody z serwisu infrastrukturalnego WeatherProvider. Konkretnie dane na temat pogody bierzemy z jakiś KILKU zewnętrznych API, z racji tego, że chcemy te dane jakoś scalać, jeśli nie wszystko jest podane, albo no mamy inny cel w tym, że pogodę bierzemy z kilku API a nie jednego. I teraz w czym jest moja zagwozdka. Załóżmy, że w module Weather mamy dtosa WeatherDto, który prezentuje pogodę i jest zwracany przez wspomniany wcześniej interfejs infrastrukturalny. Intefejs ten jest gdzie indziej implementowany przez kilku klientów API. Tylko sprawa jest taka, że każde API zwraca inną strukturę danych, więc każda implementacja tego intefejsu będzie musiała też zawierać logikę konwersji między zwracaną z API strukturą a moim WeatherDto. No i moje pytanie brzmi czy takie podejście jest ok. Bo oddzielamy się totalnie od klientów API i modułu Weather nie interesuje w ogóle to co zwracana każde z API - logika konwersji na WeatherDto znajduję się w implementacji interfejsu infrastrukturalnego WeatherProvider.
    A może lepiej zrobić tak, że dla każdego API zrobić osoby interfejs, który zwraca inną strukturę danych i te konwertery na WeatherDto potraktować jako logikę domeny ? Tylko no wtedy domena pogody jest związana jakoś z implementacją i światem zewnętrznym.

  2. Do tej pory pisząc RESTy wyglądało to mniej więcej tak, że logika była w serwisach, były jakieś assemblery czy konwertery no i niby wszytko ok, ale budować aplikację zaczynałem od zbudowania encji relacyjnej bazy. Po większej edukacji poczytałem o prawilnym podejściu, że najpierw powinno się budować logikę domeny, a encje bazodanowe powinny być na końcu jako rozwiązanie problemu. Podobnie, że serwisy i wszelkie assemblery to przeczenie obiektowości i pisanie kodu strukturalnego. Zacząłem zatem pisać sobie edukacyjnie jakąś gierkę strategiczno ekonomiczną zaczynając od domeny i strając się nie pisać kodu strukturalnego. Zrobiłem zatem np klasę Building prezentującą budynek z jego kosztem, poziomiem, czasem budowania itd. Nie ma żadnych geterów i seterów - posiada tylko metody biznesowe i wygląda to wszystko ok, ale bardzo dla mnie nieintuicyjne jest to, że ten obiekt jest niby stanowy, jest biznesową encją, ale przecież jego cykl życia to jedno zapytanie http :D I flow wygląda tak: muszę gdzieś pobrać info na temat tego budynku z jakiejś bazy, stworzyć go przez konstruktor, wykonuję biznesową metodę, która zmienia jego stan, czyli np sprawdzam czy można zbudować, rozbudowuję, wyciągam z niego dtosa, robię save w bazie i koniec. Czy to tak powinno wyglądać ?

  3. Trochę pytanie powiązane z pkt 2. Mam tą klasę Building. No i doszedłem do tego, że każdy budynek ma inne funkcje - np jedne są kopalniami, jedne produkują jednostki wojskowe, jedne coś przechowują i co tam dalej jeszcze wymyślę. Oczywiście nie będę robił dziedziczenia. Klasa Building zawiera podstawowe dane dla każdego budynku - ValueObjecty typu koszt, czas, nazwa. Resztę jego rzeczy typu to co ma robić, to co potrafi postanowiłem zrobić za pomocą kompozycji .. no i to zrodziło problemy. Mogę np zrobić intefejs Extractable i jego konkretną implementację + implementację NullObjectPattern i tą konkretną powstrzykiwać do jakiś kopalni, a Nullową do Building typu stocznia czy coś, ale jakoś średnio mi się to podoba. Oczywiście taki intefejs Extractable miałby metody typu extract(long dt).. ale jak potem taki Building skompowany zapisać do tabelki w bazie danych ha :D Trochę błądzę .. jakieś rady ?

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
1
  1. Ja bym mapował po stronie mikroserwisu który pobiera dane z danego endpointu. Tzn każdy z tych twoich serwisów wystawia identyczne API i zwraca takie samo DTO. Dzięki temu jak któryś zewnętrzny serwis się zmieni, to modyfikujesz tylko ten jeden miroserwis, a nie jakis Core twojej usługi.
  2. o_O A pomyślałeś może o tym, że gra się powinna toczyć i siedzieć w pamięci a nie wczytywać od zera przy każdym requeście? Wyobraź sobie że w strzelance ktoś stosuje takie podejście jak twoje -> za każdym razem jak jest user action (ruch myszki czy kliknięcie czy input z klawiatury) to gra wczytuje cały stan od zera, wykonuje akcje a potem zapisuje stan. Wyobrażasz sobie jaki byłby performance? ;)
  3. Ja bym prędzej zrobił generyczny interfejs Action i np. przechowywał w tych budynkach listę akcji do wykonania, a nie robił miliona property z których większość nullowa.

"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
0

Dlaczego serwisy to przeczenie obiektowości?


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

@scibi92 bo tak już jest. Serwis jest bezstanowy i dostaje niemutowalne obiekty jako dane i zwraca kolejny zestaw niemutowalnych obiektów jako wyniki, zwykle w postaci prostych DTO. Na dobrą sprawę zwykle metody takiego serwisy mogłyby być nawet i statyczne. To wszystko to jest definicja programowania proceduralnego lub nawet funkcyjnego, a z obiektowością nic wspólnego nie ma. Trik polega na tym co się dzieje "pod spodem", tzn w jaki sposób serwis realizuje swoją logikę, bo dopiero tutaj pojawia się warstwa domenowa i obiektowość. Ale jak ktoś klepie generic cruda, to nigdy tej warstwy nie ma, bo serwis ciągnie dane z jakiegoś dao i tyle ;)


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
0

@Shalom: w jaki sposób serwisy są bezstanowe? Przecież posiadają referencje do jakiś DAO czy innych serwisów i innych obiektów.

Np. UserRegisterService będzie miał UserRepository, PasswordEncoder i NotificationService


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
AC
chyba chodzi o immutable class
Shalom
Bezstanowy nie oznacza że nie ma pól. o_O Oznacza że nie przechowuje "stanu" pomiędzy operacjami.
S9
Są różne definicje. Nadal nie wiem czemu nie uznać tego za OOP
Shalom
Jejku, bo jeśli masz serwis który zawiera tylko "operacje" i serwujesz mu dane w postaci DTO to nie jest to nijak obiektowość. Obiektowość by była jakby zamiast tego serwisu mieć obiekt domenowy, który tworzysz podając odpowiednie dane a potem wykonujesz operacje w oparciu o stan tego obiektu. Od razu mówie że akcja w stylu new Cośtam(dane).calculate() też nie będzie obiektowością :P
1

Ale wg mnie te pola o których mówisz @scibi92 są i tak z definicji finalne i się nie zmieniają. Każde wywołanie jakiejś metody serwisowej nie ma żadnych danych odnośnie poprzednich wywołań czegoś z tego samego serwisu.

S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
0

No to wedlug Ciebie jak obiekt jest niemutowaly to nie może mieć nic wspolnego z OOP? :D :D :D


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
1

No ok, a jakie możesz wyróżniać przykładowe stany takiego serwisu ? Tak jak wspomniałem - cokolwiek serwis wykonał w przeszłości - obecne wywołanie jego metod nie wie nic o tym - jak z http.

0

@Shalom:

Co do punktu drugiego. Chodzi mi konkretnie o taką grę jak ogame. Załóżmy jest takie flow:

  • użytkownik chce zupgradować kopalnie metalu, zatem idzie request : /militaryBase/jakasNazwaBazy/building/METAL_MINE/upgrade
  • z bazy jest wczytywany dany militaryBase, na jego podstawie tworzę obiekty domenowe
  • sprawdzam na obiektach domenowych, czy można zbudować, w przypadku sukcesu startuję rozbudowę, przełączam stan na "budowany", odejmuję surowce i co tam jeszcze ( wszystkie metody wywoływane są na obiektach domenowych, a nie w serwisie na dtosach)
  • zapisuję zmiany do bazy: repository.save(militaryBase.dto())

W jaki sposób przy takiej grze chcesz wykonywać w pamięci i trzymać stany bazy w pamięci ?

Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0

@Niezadowolony orzeł o_O a gdzie widzisz problem? Mógłbyś przecież wczytać stan gry kiedy user się loguje i potem trzymać ten stan w pamięci i na nim operować, a z jakimś timeoutem jeśli dany stan jest nieużywany to go zapisujesz i usuwasz z pamięci. Wyobraź sobie że ktoś pisze w twoim stylu dowolny program, edytor tekstu na przykład. Za każdym wciśnieciem literki wczytujesz od nowa plik a potem zapisujesz? :D


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 3 godziny
  • Postów:2368
0
Niezadowolony orzeł napisał(a):

Od kilku lat programuję w javie, ostatnio pooglądałem trochę konferencji, poczytałem tematów, postanowiłem zmienić podejście. Mam kilka pytań:

  1. @Shalom dobrze Ci doradził.

  2. Co masz na myśli pisząc "cykl życia to jedno zapytanie http"?

Cykl życia budynku to cykl życia "biznesowy", a nie techniczny :) Oznacza to, że masz z tym cyklem związane:

  • stany: np. Planowany, W budowie, Budowa zakończona, W gotowości, Uszkodzony, W naprawie, Atakowany (co tam sobie wymyślisz)
  • przejścia między stanami

Za cyklem życia może stać maszyna stanów reagująca na zdarzenia, które mogą powodować przejście z jednego stanu do drugiego, zaś przejścia między stanami mogą wywoływać jakieś akcje.

np. Atakowany + zdarzenie: EventMissileIncoming może spowodować wyzwolenie logiki typu:

  • oblicz uszkodzenia
  • jeśli energia - uszkodzenia < paliSie -> przejdź do stanu "Plonie"

Ja pewnie bym szedł w takiej grze w modelowanie obiektów przez dodawanie im:

  • maszyn stanów reagaujących na dostarczone zdarzenia
  • akcji które mają być wykonywane w odpowiedzi na nadchodzące zdarzenia
  • properties pozwalających na wizualizację (np. kolor, typBudynku, itd. )
hcubyc
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 2 lata
0
scibi92 napisał(a):

No to wedlug Ciebie jak obiekt jest niemutowaly to nie może mieć nic wspolnego z OOP? :D :D :D

Nie to miał na myśli - niemutwalne obiekty są spoko, jeżeli to są jakieś struktury danych, ale serwisy na zasadzie - weź jednego DTO, coś tam zrób, wypluj drugiego DTO to podejście strukturalne. Nie ma w tym nic złego, dopóki cała twoja aplikacja tak nie wygląda. Tfu, nadal nie ma w tym nic złego, ale OOP to to nie jest ;)


Limitations are limitless > ##### Ola Nordmann napisał(a)
> Moim językiem ojczystym jest C++ i proszę uszanować to, że piszę po polsku.
S9
  • Rejestracja:ponad 10 lat
  • Ostatnio:5 miesięcy
  • Lokalizacja:Warszawa
  • Postów:3573
0

Zaraz, ale w każdej aplikacji napisanej w OOP są obiekty które porozumiewają się za pomocą wiadomości. Nie wiem w każdym razie kiedy już moge rozdzielić.
Skoro występuje abstrakcja, hermetyzacja i poliformizm to to jest chyba OOP? No nie wiem, jakoś np. prywatne metody czy istnienie kontraktów to bardziej z OOP kojarzy...
Ale ja może sie nie znam...


"w haśle <młody dynamiczny zespół> nie chodzi o to ile masz lat tylko jak często zmienia się skład"
hcubyc
  • Rejestracja:ponad 12 lat
  • Ostatnio:ponad 2 lata
0

Tak masz rację, ale jeżeli do tego zastosujesz anemic entities - to IMHO tak średnio. Z drugiej strony, w prostych CRUDach czy czasem w prostych domenach i tak będzie to tak wyglądało, bo obiekty nie mają zbyt wiele zachowań, ale jeżeli masz złożoną domene/biznes i i DTOsy i serwisy no to moim zdaniem po prostu można lepiej. To co mam na myśli to prostu jeżeli masz DTOsa, w serwisie go wybebeszasz ze wszystkich pól, coś tam robisz, pakujesz do kolejnego DTOsa, w kolejnym serwisie to samo to to wtedy tak trochę c**** nie hermetyzacja. Prosty przykład o co mi chodzi co uważam, za złe - masz obiekt, który może być aktywny lub nie i zamiast np. myCoolObject.activate() robisz myCoolObject.setActive(true), tak samo dla bardziej skomplikowanych zachowań nie enkapsuluje się zachowania w obiekcie, tylko zawsze jest jakiś magiczny serwis, który setterami naparza we wszystko co się rusza


Limitations are limitless > ##### Ola Nordmann napisał(a)
> Moim językiem ojczystym jest C++ i proszę uszanować to, że piszę po polsku.
edytowany 2x, ostatnio: hcubyc
AC
  • Rejestracja:prawie 9 lat
  • Ostatnio:ponad 6 lat
  • Postów:33
0

@scibi92 Chodzi zapewne kwestie związane np. side effect, czy stopnia komplikacji testów w OOP, czego nie ma w funkcyjnym paradygmacie. Może to kwestia architektury, że istnieją inne rozwiązania niż tylko "encja na twarz i pchasz", np. Event Driven Design - programowanie reaktywne.

Bambo
  • Rejestracja:ponad 10 lat
  • Ostatnio:7 miesięcy
  • Postów:779
0

@Shalom:

Twierdzisz, żeby nie zapisywać od razu w bazie, tylko w pamięci.

A jeśli serwer padnie i ważne zmiany (np. wybudowanie ważnego budynku) nie zostaną zapisane do bazy czy coś ?

Myślisz, że w takim Ogame, żadna akcja typu wybudowanie, update czegoś itd. nie idzie od razu do bazy ?

PS. Sory za odkopanie starego wątku, ale tak z nudów w pracy sobie przeglądam, natrafiłem na to i sam miałem ostatnio podobną rozkminę, że przecież każdy request to jakby osobna historia, więc się zastanawiałem, gdzie w takim requeście jest miejsce na rozbudowaną logikę domenową skoro to trwa tak szybko.

edytowany 1x, ostatnio: Bambo
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:prawie 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
2

@Bambo nie rozumiesz. Jedno z drugim nie ma nic wspólnego. Czym innym jest prowadzenie gry na podstawie danych w pamięci a czym innym jest periodyczne zapisywanie stanu. Jedno drugiego nie wyklucza.
Czy jak edytujesz plik w Wordzie to myślisz ze za każdym razem jak wpiszesz literkę to dane są zapisywane na dysk i z niego wczytywane? Czy jednak stan jest w pamieci i na nim operujesz, a w tle działa proces który co jakiś czas zapisuje dane (lub też pewne eventy powodują zapisanie stanu)?

Idea jest właśnie taka, ze w stan aplikacji jest w pamięci, ale jest co jakiś czas zapisywany. Możesz zapisywać stan, czy też eventy które go zmieniają, bez różnicy, ale chodzi o to żeby nie pisać i czytać non stop bo to nie ma sensu.


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
edytowany 1x, ostatnio: Shalom
YA
  • Rejestracja:prawie 10 lat
  • Ostatnio:około 3 godziny
  • Postów:2368
0
Bambo napisał(a):

A jeśli serwer padnie i ważne zmiany (np. wybudowanie ważnego budynku) nie zostaną zapisane do bazy czy coś ?

Myślisz, że w takim Ogame, żadna akcja typu wybudowanie, update czegoś itd. nie idzie od razu do bazy ?

Problem rozbijasz na mniejsze:

  • logiki biznesowej (jak działa Twoja gra/aplikacja)
  • infrastruktury (jak sprawić, by nie było Single Point of Failure, albo żeby utrata danych była jak najmniejsza, o ile jest akceptowalna - co innego fail dla pojedyńczego klienta, a co innego dla 90%)

Request może być pakowany do kolejki na systemie plików/ "pamięć" może być replikowana na wiele maszyn itd. Są różne wymagania i różne techniki.

danek
  • Rejestracja:ponad 10 lat
  • Ostatnio:6 miesięcy
  • Lokalizacja:Poznań
  • Postów:797
0

@Shalom
Czy dobrym pomysłem byłoby tu użycie repozytorium (czy czegoś podobnego), tak, żeby kod domenowy nie musiał wiedzieć czy pod spodem dane faktycznie lecą do bazy, czy są tylko trzymane w pamięci?


Spring? Ja tam wole mieć kontrole nad kodem ᕙ(ꔢ)ᕗ
Haste - mała biblioteka do testów z czasem.
hcubyc
IMHO repozytorium jak najbardziej
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)