Strona główna / Artykuły / Wskazówki praktyczne: Jak działa MCP: Szczegółowe omówienie z kodem

Wskazówki praktyczne: Jak działa MCP: Szczegółowe omówienie z kodem

Praktyczne wskazówki: Jak działa MCP: szczegółowe omówienie z kodem – umowy, sprawdzania oraz miejsca na wstawianie kodu dla zespołów wdrażających ten wzorzec.

3070 słów

To przewodnik odtwarza proces od surowców do gotowego systemu w ramach tematu: Jak działa MCP: Szczegółowe omówienie z kodem. Główny nacisk kładziony jest na konkretne kroki, wyraźne sprawdzenia oraz kod, który można bez problemu dodać do repozytorium, nie musząc zgadywać jego przeznaczenia. W fazie przeglądu należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed zmianą kodu. Operatorzy powinni móc ponownie wykonać dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Obok wyników funkcjonalnych należy rejestrować czas wykonywania oraz koszt tokenów lub zapytań. Wczesna widoczność kosztów zapobiega nieoczekiwanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do współdzielonych środowisk.

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": {}
}
{
  "jsonrpc": "2.0",
  "id": 1,
  "result": {
    "tools": [
      {
        "name": "search_web",
        "description": "Search the web for a given query",
        "inputSchema": {
          "type": "object",
          "properties": {
            "query": { "type": "string" }
          },
          "required": ["query"]
        }
      }
    ]
  }
}
{
  "jsonrpc": "2.0",
  "id": 2,
  "method": "tools/call",
  "params": {
    "name": "search_web",
    "arguments": {
      "query": "latest news on MCP protocol"
    }
  }
}
{
  "jsonrpc": "2.0",
  "id": 2,
  "result": {
    "content": [
      {
        "type": "text",
        "text": "Anthropic released MCP in Nov 2024 as an open standard..."
      }
    ]
  }
}

Co to jest FastMCP?

Gdy przechodzisz przez etap „Co to jest FastMCP”, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Przechowuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Zapisuj nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdej wywołania. Bez takich informacji debugowanie pętli agenta trwa godzinami.

from fastmcp import FastMCP

mcp = FastMCP("My Server")   # creates the server

@mcp.tool()                  # registers the function as an MCP tool
def add(a: float, b: float) -> float:
    """Add two numbers."""    # docstring → tool description sent to the LLM
    return a + b             # type hints → JSON Schema sent to the LLM

mcp.run()                    # starts the stdio message loop

Trzy podstawowe elementy MCP

Gdy przechodzisz przez etap trzech podstawowych elementów MCP, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zdokumentuj zarówno ścieżkę prawidłowego działania, jak i ścieżkę naprawczą. Próby ponowne, kontrola przez ludzi oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dopiero późniejszej optymalizacji. Zapisuj nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdej wywołania. Bez takich informacji debugowanie agenta może trwać godzinami.

# servers/math_server.py

@mcp.tool()
def divide(a: float, b: float) -> float:
    """Divide a by b. Raises an error if b is zero."""
    if b == 0:
        raise ValueError("Cannot divide by zero")
    return a / b
# servers/math_server.py

@mcp.resource("math://constants")
def get_math_constants() -> str:
    """Common mathematical constants."""
    return f"π = {math.pi}\n e = {math.e}\n ..."

@mcp.resource("math://formulas/{category}")
def get_formulas(category: str) -> str:
    """Retrieve mathematical formulas by category (geometry | algebra | statistics)."""
    catalog = {
        "geometry": (
            "Geometry Formulas:\n"
            "  Circle area:            A = π × r²\n"
            "  Circle circumference:   C = 2π × r\n"
            "  Rectangle area:         A = length × width\n"
            "  Triangle area:          A = (base × height) / 2\n"
            "  Sphere volume:          V = (4/3) × π × r³\n"
        ),
        "algebra": (
            "Algebra Formulas:\n"
            "  Quadratic formula:      x = (−b ± √(b²−4ac)) / 2a\n"
            "  Difference of squares:  a²−b² = (a+b)(a−b)\n"
            "  Perfect square:         (a+b)² = a²+2ab+b²\n"
            "  Sum of arithmetic seq:  S = n(a₁+aₙ)/2\n"
        ),
        "statistics": (
            "Statistics Formulas:\n"
            "  Mean:       μ = Σx / n\n"
            "  Variance:   σ² = Σ(x−μ)² / n\n"
            "  Std Dev:    σ = √(Σ(x−μ)² / n)\n"
            "  Z-score:    z = (x−μ) / σ\n"
        ),
    }
    return catalog.get(
        category,
        f"Unknown category '{category}'. Available: geometry, algebra, statistics",
    )
# servers/math_server.py

@mcp.prompt()
def math_tutor(difficulty: str = "intermediate") -> str:
    return (
        f"You are an expert math tutor for {difficulty}-level students. "
        "Break every problem into numbered steps..."
    )

Podsumowanie serwera

Gdy przechodzisz przez etap podsumowania serwera, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok się nie powiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Zapisuj nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdego wywołania. Bez takich informacji debugowanie agenta trwa godzinami.

Z perspektywy klienta

Gdy przechodzisz przez etap „Od klienta”, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadania. Zapisuj nazwę narzędzia, hash argumentów, czas opóźnienia oraz wynik każdej wywołania. Bez takich informacji debugowanie zajmuje godziny.

You type a query
      │
      ▼
main.py                    ← entry point, parses args, kicks off async loop
      │
      ▼
client/agent.py            ← spawns 3 MCP servers, builds the agent, invokes it
      │           │
      │           ▼
      │    utils/tracker.py ← fires on every LLM call, tool call, and result
      │
      ▼
LangGraph ReAct loop       ← think → call tool → observe → repeat
      │
      ▼
servers/{math,text,data}_server.py   ← each runs as an isolated subprocess

Krok 1 — punkt wejścia

Gdy przechodzisz przez pierwszy krok, czyli etap wprowadzenia, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Obok wyników funkcjonalnych zapisz czas trwania oraz koszt tokena lub zapytania. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z wersji demonstracyjnej do środowisk współdzielonych. Zapisuj nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdego wywołania. Bez takich informacji debugowanie agenta w pętlach marnuje godziny.

async def _run(queries: list) -> None:
    from client.agent import run_query   # imported here (late) to keep startup fast
    for i, q in enumerate(queries):
        await run_query(q)

def main() -> None:
    ...
    asyncio.run(_run(queries))
Generate 8 random numbers between 5 and 50 using seed=42,
then calculate their statistics, and tell me if there are any outliers.
python3 main.py --query "Generate 8 random numbers between 5 and 50 using seed=42, \
then calculate their statistics, and tell me if there are any outliers."
╭────────────────────────────── 🔌  MCP Example ───────────────────────────────╮
│ Multi-Server MCP Demo                                                        │
│                                                                              │
│ Three FastMCP servers, each exposing tools + resources + prompts:            │
│   ●  Math Server   — add, subtract, multiply, divide, power, sqrt,           │
│ percentage                                                                   │
│   ●  Text Server   — count_words, word_frequency, reverse, transform,        │
│ extract_emails                                                               │
│   ●  Data Server   — generate_numbers, calculate_statistics, find_outliers,  │
│ normalise                                                                    │
│                                                                              │
│ Stack : FastMCP · LangChain · LangGraph · OpenAI · Rich                      │
│ Track : live Rich panels + JSONL log files under logs/                       │
╰──────────────────────────────────────────────────────────────────────────────╯

Krok 2 — Budowa agenta

Gdy przechodzisz do kroku 2 – budowania platformy, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Trzymaj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności czytania całej struktury. Zapisuj nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdej wywołania. Bez takich informacji debugowanie agentów trwa godzinami.

log_file = str(LOGS_DIR / f"run_{int(time.time())}.jsonl")
tracker = MCPTracker(log_file=log_file)
╭──── 💬  USER QUERY ────╮
│ Generate 8 random...   │
╰────────────────────────╯
def _server_config() -> Dict[str, Any]:
    silent_env = {**os.environ, "FASTMCP_LOG_LEVEL": "ERROR"}
    return {
        "math_server": {
            "command": sys.executable,
            "args": ["servers/math_server.py"],
            "transport": "stdio",
            "env": silent_env,
        },
        "text_server": { ... },
        "data_server":  { ... },
    }
client = MultiServerMCPClient(_server_config())
tools = await client.get_tools()
Connected to 3 servers (math_server, text_server, data_server) with 19 tools: add, subtract, multiply,
divide, power, square_root, calculate_percentage, count_words, word_frequency, reverse_text,
transform_case, find_and_replace, extract_emails, count_vowels_consonants, generate_numbers,
calculate_statistics, find_outliers, sort_values, normalize_values
model = ChatOpenAI(model=model_name, temperature=0)
agent = create_react_agent(model, tools)
START
  │
  ▼
[call_model]  ─── no tool call ──▶  END
      │
  tool call requested
      │
      ▼
[call_tools]
      │
      ▼
[call_model]  (loop again with tool result in context)
config = {"callbacks": [tracker]}
result = await agent.ainvoke({"messages": [("human", query)]}, config=config)

Krok 3 – Obserwowanie wszystkiego w czasie rzeczywistym

Gdy przechodzisz przez etap nr 3, polegający na obserwowaniu całego procesu, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zdokumentuj zarówno prawidłowy przebieg, jak i ścieżkę naprawczą. Próby ponowne, kontrola przez ludzi oraz obsługa wiadomości błędowych stanowią część produktu, a nie elementy dodawane później. Zapisuj nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdej wywołania. Bez tych informacji debugowanie agentów trwa godzinami.

agent.ainvoke() called
      │
      ├─▶ on_chain_start()       "▶ AGENT STARTED" panel
      │
      ├─▶ on_chat_model_start()  "🤖 LLM CALL #1" panel  (timer starts)
      ├─▶ on_llm_end()           "LLM responded ⏱ 1.23s → will call: add, multiply"
      │
      ├─▶ on_tool_start()        "🔧 TOOL CALL #1" panel  (timer starts)
      ├─▶ on_tool_end()          "✓ TOOL RESULT ⏱ 0.01s" panel
      │
      ├─▶ on_tool_start()        (second tool, if any)
      ├─▶ on_tool_end()
      │
      ├─▶ on_chat_model_start()  "🤖 LLM CALL #2" (LLM synthesises final answer)
      ├─▶ on_llm_end()           no tools this time → loop ends
      │
      └─▶ agent.ainvoke() returns
TOOL_SERVER_MAP = {
    "add":        "math_server",
    "count_words": "text_server",
    "generate_numbers": "data_server",
    ...
}
SERVER_COLORS = {
    "math_server": "cyan",
    "text_server":  "green",
    "data_server":  "yellow",
}
── 🤖  LLM CALL  #1  model=gpt-5-mini   messages=1 ──╮
│  Role    Content preview                             │
│  Human   Generate 8 random numbers between 5 and 50… │
╰──────────────────────────────────────────────────────╯
  LLM responded  ⏱ 5.35s  → will call: generate_numbers
{
  "name": "generate_numbers",
  "arguments": {"count": 8, "min_val": 5, "max_val": 50, "seed": 42}
}
╭── 🔧  TOOL CALL  #1 ──────────────────╮
│ Tool  :  generate_numbers             │
│ Server:  data_server                  │
│ Args  :                               │
│ {'count': 8, 'min_val': 5,            │
│  'max_val': 50, 'seed': 42}           │
╰───────────────────────────────────────╯
{"method": "tools/call", "params": {"name": "generate_numbers",
  "arguments": {"count": 8, "min_val": 5, "max_val": 50, "seed": 42}}}
╭── ✓  TOOL RESULT  ⏱ 0.63s ────────────────────────────╮
│ [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91] │
╰──────────────────────────────────────────────────────────╯
random.seed(42)
return [round(random.uniform(5, 50), 2) for _ in range(8)]
# → [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91]
╭── 🤖  LLM CALL  #2  model=gpt-5-mini   messages=3 ──╮
│  Role    Content preview                             │
│  Human   Generate 8 random numbers…                 │
│  AI      (the tool-call decision)                    │
│  Tool    [33.77, 6.13, 17.38, ...]                   │
╰──────────────────────────────────────────────────────╯
Tool  : calculate_statistics
Server: data_server
Args  : {'numbers': [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91]}
Result: {"count":8, "min":6.13, "max":45.15, "mean":24.9962,
         "median":25.575, "std_dev":14.8181, "variance":219.5755,
         "range":39.02, "q1":15.04, "q3":38.14}
Tool  : find_outliers
Server: data_server
Args  : {'numbers': [...], 'threshold': 2}
Result: {"outliers": [], "outlier_count": 0,
         "total_checked": 8, "mean": 24.9962, "std_dev": 14.8181}
╭── 🤖  LLM CALL  #4  messages=7 ──╮
│  Human / AI / Tool                │
│  AI    / Tool                     │
│  AI    / Tool                     │
╰───────────────────────────────────╯
  LLM responded  ⏱ 30.25s
╭── ✅  FINAL ANSWER ───────────────────────────────╮
│ Random numbers: [33.77, 6.13, 17.38, ...]        │
│ Mean: 24.9962 / Median: 25.575 / Std Dev: 14.8181│
│ Outliers: none (all |z| < 2)                     │
╰───────────────────────────────────────────────────╯
╭─────────────────────────────────────────────────────╮
│ LLM Calls   4                                       │
│ Tool Calls  3                                       │
│ Total Time  42.25s                                  │
│ Log File    logs/run_1776864980.jsonl               │
╰─────────────────────────────────────────────────────╯

Pełna sekwencja wiadomości

Gdy przechodzisz przez etap pełnej sekwencji wiadomości, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok się nie powiedzie, błąd powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Zapisuj nazwę narzędzia, hash argumentów, opóźnienie oraz wynik każdego wywołania. Debugowanie bez takich informacji marnuje godziny. Gdy przechodzisz przez etap pełnej sekwencji wiadomości, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy proces przechodzi z środowiska demonstracyjnego do wspólnych środowisk.

1  HumanMessage   "Generate 8 random numbers…"
2  AIMessage      [tool_call: generate_numbers({count:8, min:5, max:50, seed:42})]
3  ToolMessage    [33.77, 6.13, 17.38, 15.04, 38.14, 35.45, 45.15, 8.91]
4  AIMessage      [tool_call: calculate_statistics({numbers:[...]})]
5  ToolMessage    {count:8, mean:24.9962, std_dev:14.8181, ...}
6  AIMessage      [tool_call: find_outliers({numbers:[...], threshold:2})]
7  ToolMessage    {outliers:[], outlier_count:0, ...}
8  AIMessage      "Here are the results. Random numbers: …"   ← final answer

Log JSONL

Etap logowania w formacie JSONL funkcjonuje najlepiej, gdy traktowany jest jako mierzalna powierzchnia do analizy. Zapisz jeden idealny przykład działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Utrzymuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny poufnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury. Udostępniaj narzędzia o wąskich schematach i wyraźnych etykietach dotyczących efektów ubocznych. Hostowie muszą wiedzieć, które wywołania zmieniają stan systemu, zanim automatycznie je zatwierdzą.

{"timestamp": "...", "event": "agent_start",  "data": {"runnable": "LangGraph", "run_id": "..."}}
{"timestamp": "...", "event": "llm_call",     "data": {"call_number": 1, "model": "gpt-5-mini", "messages": 1}}
{"timestamp": "...", "event": "llm_end",      "data": {"elapsed": "5.35s", "tool_calls_requested": ["generate_numbers"]}}
{"timestamp": "...", "event": "tool_start",   "data": {"call_number": 1, "tool": "generate_numbers", "server": "data_server", "args": "..."}}
{"timestamp": "...", "event": "tool_end",     "data": {"elapsed": "0.63s", "output_preview": "[33.77, 6.13, ...]"}}
{"timestamp": "...", "event": "llm_call",     "data": {"call_number": 2, "model": "gpt-5-mini", "messages": 3}}
...
{"timestamp": "...", "event": "run_summary",  "data": {"llm_calls": 4, "tool_calls": 3, "total_elapsed": "42.25s"}}

Źródła

Etap źródeł działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię. Zapisz jeden idealny przypadek działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres pracy. Zdokumentuj zarówno pomyślny, jak i awaryjny scenariusz działania produktu. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości nieodrzuconych stanowią część produktu, a nie elementy dodawane później. Używaj narzędzi o wąskich schematach i wyraźnych etykietach dotyczących efektów ubocznych. Hostowie muszą wiedzieć, które wywołania zmieniają stan systemu, zanim je automatycznie zatwierdzą.

Wiadomość od naszego założyciela

Wiadomość A z naszej platformy funkcjonuje najlepiej, gdy traktowana jest jako mierzalna powierzchnia. Zapisz jeden idealny zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres. Wolimy małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy jakiś krok zawiedzie, awaria powinna wskazywać na konkretną odpowiedzialność, a nie na skomplikowany łańcuch operacji. Używaj narzędzi o wąskich schematach oraz z wyraźnymi etykietami efektów ubocznych. Hostowie muszą wiedzieć, które wywołania zmieniają stan, zanim automatycznie je zatwierdzą. Wiadomość A z naszej platformy funkcjonuje najlepiej, gdy traktowana jest jako mierzalna powierzchnia. Zapisz jeden idealny zapis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres. Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy proces przechodzi z wersji demonstracyjnej do środowisk współdzielonych.

Lista kontrolna operacyjna

Etap listy kontrolnej operacyjnej działa najlepiej, gdy traktuje się go jako mierzalną powierzchnię. Zapisz jeden idealny przepis działania, jeden przypadek awarii oraz notatkę dotyczącą cofnięcia działań, zanim rozszerzysz zakres.

Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nazwij poszczególne elementy, zdefiniuj kryteria sukcesu i odrzuć ciche, częściowe ukończenie zadań.

Używaj narzędzi o wąskich schematach oraz z wyraźnymi etykietami opisującymi efekty uboczne. Hostowie muszą wiedzieć, które wywołania zmieniają stan systemu, zanim automatycznie je zatwierdzą.

Gdy budżet na to pozwala, dodaj test dymny, który symuluje kluczową ścieżkę w procesie CI przy użyciu fixtur, a nie rzeczywistych, płatnych API.

Zapisuj czasy wykonywania oraz koszt tokenów lub zapytań obok wyników funkcjonalnych. Wczesna widoczność kosztów zapobiega niespodziewanym rachunkom, gdy ścieżka przechodzi z wersji demonstracyjnej do środowisk współdzielonych.

Ujawniaj narzędzia o wąskich schematach oraz z wyraźnymi etykietami efektów ubocznych. Hostowie muszą wiedzieć, które wywołania modyfikują stan, zanim dokonają automatycznej aprobaty.

Zanim przejdziesz na nową wersję stacku, zamroź wersje, utwórz „złoty zapis” dla kluczowych ścieżek oraz potwierdź kroki odwracania zmian. Środowiska współdzielone wymagają ograniczeń szybkości, weryfikacji przynależności oraz jasno określonego właściciela odpowiedzialnego za rotację haseł. Wolisz nudną niezawodność od sprytnych, jednorazowych demonstracji.

Uwaga dotycząca c7efc4f69698: trzymaj klucze dostawcy poza repozytorium, ustaw ograniczenie liczby tokenów na sesję oraz przechowuj zapisy obok plików przygotowawczych do testowania, aby późniejsze zamiany modeli pozostały porównywalne.

Dla etapu 0 notatki dotyczącej wzmocnienia bezpieczeństwa należy zdefiniować dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie uruchomić ten krok od znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Należy udokumentować zarówno prawidłowy przebieg działania, jak i ścieżkę naprawczą. Próby ponownych działań, kontrolne punkty ludzkie oraz obsługa wiadomości błędnych stanowią część produktu, a nie elementy dodawane później.

Szczegół wzmocnienia bezpieczeństwa 0/888: należy zmierzyć czas wykonywania operacji, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecydować o utrzymaniu zmiany na podstawie ustalonego zestawu pytań, a nie opisów przypadków.

Gdy przechodzisz przez pierwszy etap notatki dotyczącej wzmocnienia bezpieczeństwa, najpierw zapisz umowę: wymagane dane wejściowe, sygnał sukcesu oraz to, co dzieje się w przypadku częściowego niepowodzenia. Taka lista kontrolna zapewnia uczciwość późniejszych zmian w kodzie. Traktuj ten etap jako umowę pomiędzy danymi wejściowymi a zweryfikowanymi wynikami. Nadaj nazwy poszczególnym elementom, zdefiniuj kryteria sukcesu i odrzuć przypadki częściowego ukończenia bez żadnych informacji.

Szczegół 1/888 dotyczący wzmocnienia bezpieczeństwa: zmierz czas wykonywania, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecyduj, czy zachować zmianę na podstawie ustalonego zestawu pytań, a nie jedynie informacji anegdotycznych.

Etap notatki dotyczącej wzmocnienia bezpieczeństwa nr 2 działa najlepiej, gdy jest traktowany jako mierzalna powierzchnia do analizy. Zapisz jeden idealny przepływ działania, jeden przypadek niepowodzenia oraz notatkę dotyczącą cofnięcia zmian, zanim rozszerzysz zakres prac. Utrzymuj konfigurację poza kodem aplikacji. Pliki środowiskowe, magazyny tajnych danych oraz flagi funkcjonalne powinny znajdować się w jednym miejscu, które operatorzy mogą sprawdzić bez konieczności przeglądania całej struktury.

Szczegół wzmocnienia 2/888: zmierz czas wykonywania, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecyduj, czy zachować zmianę na podstawie ustalonego zestawu pytań, a nie jedynie anegdoty.

W trzecim etapie notatki dotyczącej wzmocnienia określ dane wejściowe, osobę odpowiedzialną za dany krok oraz kryteria zakończenia przed modyfikacją kodu. Operatorzy powinni móc ponownie wykonać dany krok na podstawie znanego punktu kontrolnego, bez konieczności zgadywania ukrytego stanu. Wolno preferować małe, testowalne jednostki zamiast rozbudowanych skryptów. Gdy dany krok zawiedzie, powód awarii powinien wskazywać na konkretną odpowiedzialność, a nie na skomplikowany proces.

Szczegół wzmocnienia 3/888: zmierz czas wykonywania, klasę błędu oraz zużycie tokenów dla tej notatki, a następnie zdecyduj, czy zachować zmianę na podstawie ustalonego zestawu pytań, a nie jedynie anegdoty.

Literatura pokrewna