찾다
백엔드 개발Golang주문 처리 시스템 구현: 기반 구축 부분

Implementing an Order Processing System: Part  Setting Up the Foundation

1. 소개 및 목표

마이크로서비스 오케스트레이션을 위해 Temporal을 사용한 정교한 주문 처리 시스템 구현에 관한 포괄적인 블로그 시리즈의 첫 번째 부분에 오신 것을 환영합니다. 이 시리즈에서는 복잡하고 장기 실행되는 워크플로를 처리할 수 있는 강력하고 확장 가능하며 유지 관리 가능한 시스템을 구축하는 과정의 복잡함을 살펴보겠습니다.

우리의 여정은 프로젝트의 기반을 마련하는 것부터 시작됩니다. 이 게시물이 끝나면 Golang에서 구현되고 워크플로 조정을 위해 Temporal과 통합되고 Postgres 데이터베이스에서 지원되는 완전한 기능의 CRUD REST API를 갖게 됩니다. 우리는 최신 도구와 모범 사례를 사용하여 코드베이스를 깔끔하고 효율적이며 유지 관리하기 쉽게 만들 것입니다.

이 게시물의 목표:

  1. Go 모듈을 사용하여 잘 구성된 프로젝트 설정
  2. Gin 및 oapi-codegen을 사용하여 기본 CRUD API 구현
  3. Postgres 데이터베이스 설정 및 마이그레이션 구현
  4. 데이터베이스 상호작용을 통해 간단한 임시 워크플로우 생성
  5. 더 나은 테스트 용이성과 유지 관리성을 위해 종속성 주입 구현
  6. Docker를 사용하여 애플리케이션 컨테이너화
  7. docker-compose를 사용하여 완전한 로컬 개발 환경 제공

자세히 알아보고 주문 처리 시스템 구축을 시작해 보세요!

2. 이론적 배경과 개념

구현을 시작하기 전에 사용할 주요 기술과 개념을 간략하게 살펴보겠습니다.

골랑

Go는 단순성, 효율성 및 탁월한 동시 프로그래밍 지원으로 잘 알려진 정적으로 유형이 지정되고 컴파일된 언어입니다. 표준 라이브러리와 강력한 에코시스템은 마이크로서비스 구축을 위한 탁월한 선택입니다.

일시적인

Temporal은 분산 애플리케이션 개발을 단순화하는 마이크로서비스 오케스트레이션 플랫폼입니다. 이를 통해 복잡하고 오래 실행되는 워크플로를 간단한 절차 코드로 작성하여 실패와 재시도를 자동으로 처리할 수 있습니다.

진 웹 프레임워크

Gin은 Go로 작성된 고성능 HTTP 웹 프레임워크입니다. 훨씬 더 나은 성능과 낮은 메모리 사용량을 갖춘 마티니와 유사한 API를 제공합니다.

OpenAPI 및 oapi-codegen

OpenAPI(이전의 Swagger)는 RESTful 웹 서비스를 설명, 생성, 소비 및 시각화하기 위한 기계 판독 가능 인터페이스 파일에 대한 사양입니다. oapi-codegen은 OpenAPI 3.0 사양에서 Go 코드를 생성하는 도구로, 이를 통해 API 계약을 먼저 정의하고 서버 스텁 및 클라이언트 코드를 생성할 수 있습니다.

sqlc

sqlc는 SQL에서 유형이 안전한 Go 코드를 생성합니다. 이를 통해 일반 SQL 쿼리를 작성하고 완전히 유형이 안전한 Go 코드를 생성하여 데이터베이스와 상호 작용할 수 있으므로 런타임 오류 가능성이 줄어들고 유지 관리성이 향상됩니다.

포스트그레스

PostgreSQL은 신뢰성, 기능 견고성 및 성능으로 잘 알려진 강력한 오픈 소스 객체 관계형 데이터베이스 시스템입니다.

도커 및 도커 작성

Docker를 사용하면 애플리케이션과 해당 종속성을 컨테이너에 패키징하여 다양한 환경에서 일관성을 보장할 수 있습니다. docker-compose는 로컬 개발 환경을 설정하는 데 사용할 다중 컨테이너 Docker 애플리케이션을 정의하고 실행하기 위한 도구입니다.

이제 기본 사항을 알아보았으니 시스템 구현을 시작해 보겠습니다.

3. 단계별 구현 가이드

3.1 프로젝트 구조 설정

먼저 프로젝트 디렉터리를 만들고 기본 구조를 설정해 보겠습니다.

mkdir order-processing-system
cd order-processing-system

# Create directory structure
mkdir -p cmd/api \
         internal/api \
         internal/db \
         internal/models \
         internal/service \
         internal/workflow \
         migrations \
         pkg/logger \
         scripts

# Initialize Go module
go mod init github.com/yourusername/order-processing-system

# Create main.go file
touch cmd/api/main.go

이 구조는 표준 Go 프로젝트 레이아웃을 따릅니다.

  • cmd/api: 기본 애플리케이션 진입점을 포함합니다
  • 내부: 이 프로젝트에만 해당되며 다른 프로젝트에서 가져올 수 없는 패키지를 저장합니다
  • migrations: 데이터베이스 마이그레이션 파일을 저장합니다
  • pkg: 다른 프로젝트에서 가져올 수 있는 패키지가 포함되어 있습니다
  • 스크립트: 개발 및 배포를 위한 유틸리티 스크립트를 보관합니다

3.2 메이크파일 생성

일반적인 작업을 단순화하기 위해 Makefile을 만들어 보겠습니다.

touch Makefile

Makefile에 다음 콘텐츠를 추가하세요.

.PHONY: generate build run test clean

generate:
    @echo "Generating code..."
    go generate ./...

build:
    @echo "Building..."
    go build -o bin/api cmd/api/main.go

run:
    @echo "Running..."
    go run cmd/api/main.go

test:
    @echo "Running tests..."
    go test -v ./...

clean:
    @echo "Cleaning..."
    rm -rf bin

.DEFAULT_GOAL := build

이 Makefile은 코드 생성, 애플리케이션 빌드, 실행, 테스트 실행 및 빌드 아티팩트 정리를 위한 대상을 제공합니다.

3.3 기본 CRUD API 구현

3.3.1 OpenAPI 사양 정의

api/openapi.yaml이라는 파일을 생성하고 API 사양을 정의합니다.

openapi: 3.0.0
info:
  title: Order Processing API
  version: 1.0.0
  description: API for managing orders in our processing system

paths:
  /orders:
    get:
      summary: List all orders
      responses:
        '200':
          description: Successful response
          content:
            application/json:    
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Order'
    post:
      summary: Create a new order
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreateOrderRequest'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'

  /orders/{id}:
    get:
      summary: Get an order by ID
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '404':
          description: Order not found
    put:
      summary: Update an order
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateOrderRequest'
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Order'
        '404':
          description: Order not found
    delete:
      summary: Delete an order
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: integer
      responses:
        '204':
          description: Successful response
        '404':
          description: Order not found

components:
  schemas:
    Order:
      type: object
      properties:
        id:
          type: integer
        customer_id:
          type: integer
        status:
          type: string
          enum: [pending, processing, completed, cancelled]
        total_amount:
          type: number
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    CreateOrderRequest:
      type: object
      required:
        - customer_id
        - total_amount
      properties:
        customer_id:
          type: integer
        total_amount:
          type: number
    UpdateOrderRequest:
      type: object
      properties:
        status:
          type: string
          enum: [pending, processing, completed, cancelled]
        total_amount:
          type: number

이 사양은 주문에 대한 기본 CRUD 작업을 정의합니다.

3.3.2 API 코드 생성

oapi-codegen 설치:

go install github.com/deepmap/oapi-codegen/cmd/oapi-codegen@latest

Generate the server code:

oapi-codegen -package api -generate types,server,spec api/openapi.yaml > internal/api/api.gen.go

This command generates the Go code for our API, including types, server interfaces, and the OpenAPI specification.

3.3.3 Implement the API Handler

Create a new file internal/api/handler.go:

package api

import (
    "net/http"

    "github.com/gin-gonic/gin"
)

type Handler struct {
    // We'll add dependencies here later
}

func NewHandler() *Handler {
    return &Handler{}
}

func (h *Handler) RegisterRoutes(r *gin.Engine) {
    RegisterHandlers(r, h)
}

// Implement the ServerInterface methods

func (h *Handler) GetOrders(c *gin.Context) {
    // TODO: Implement
    c.JSON(http.StatusOK, []Order{})
}

func (h *Handler) CreateOrder(c *gin.Context) {
    var req CreateOrderRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    // TODO: Implement order creation logic
    order := Order{
        Id: 1,
        CustomerId: req.CustomerId,
        Status: "pending",
        TotalAmount: req.TotalAmount,
    }

    c.JSON(http.StatusCreated, order)
}

func (h *Handler) GetOrder(c *gin.Context, id int) {
    // TODO: Implement
    c.JSON(http.StatusOK, Order{Id: id})
}

func (h *Handler) UpdateOrder(c *gin.Context, id int) {
    var req UpdateOrderRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    // TODO: Implement order update logic
    order := Order{
        Id: id,
        Status: *req.Status,
    }

    c.JSON(http.StatusOK, order)
}

func (h *Handler) DeleteOrder(c *gin.Context, id int) {
    // TODO: Implement
    c.Status(http.StatusNoContent)
}

This implementation provides a basic structure for our API handlers. We’ll flesh out the actual logic when we integrate with the database and Temporal workflows.

3.4 Setting Up the Postgres Database

3.4.1 Create a docker-compose file

Create a docker-compose.yml file in the project root:

version: '3.8'

services:
  postgres:
    image: postgres:13
    environment:
      POSTGRES_USER: orderuser
      POSTGRES_PASSWORD: orderpass
      POSTGRES_DB: orderdb
    ports:
      - "5432:5432"
    volumes:
      - postgres_data:/var/lib/postgresql/data

volumes:
  postgres_data:

This sets up a Postgres container for our local development environment.

3.4.2 Implement Database Migrations

Install golang-migrate:

go install -tags 'postgres' github.com/golang-migrate/migrate/v4/cmd/migrate@latest

Create our first migration:

migrate create -ext sql -dir migrations -seq create_orders_table

Edit the migrations/000001_create_orders_table.up.sql file:

CREATE TABLE orders (
    id SERIAL PRIMARY KEY,
    customer_id INTEGER NOT NULL,
    status VARCHAR(20) NOT NULL,
    total_amount DECIMAL(10, 2) NOT NULL,
    created_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP WITH TIME ZONE DEFAULT CURRENT_TIMESTAMP
);

CREATE INDEX idx_orders_customer_id ON orders(customer_id);
CREATE INDEX idx_orders_status ON orders(status);

Edit the migrations/000001_create_orders_table.down.sql file:

DROP TABLE IF EXISTS orders;

3.4.3 Run Migrations

Add a new target to our Makefile:

migrate-up:
    @echo "Running migrations..."
    migrate -path migrations -database "postgresql://orderuser:orderpass@localhost:5432/orderdb?sslmode=disable" up

migrate-down:
    @echo "Reverting migrations..."
    migrate -path migrations -database "postgresql://orderuser:orderpass@localhost:5432/orderdb?sslmode=disable" down

Now we can run migrations with:

make migrate-up

3.5 Implementing Database Operations with sqlc

3.5.1 Install sqlc

go install github.com/kyleconroy/sqlc/cmd/sqlc@latest

3.5.2 Configure sqlc

Create a sqlc.yaml file in the project root:

version: "2"
sql:
  - engine: "postgresql"
    queries: "internal/db/queries.sql"
    schema: "migrations"
    gen:
      go:
        package: "db"
        out: "internal/db"
        emit_json_tags: true
        emit_prepared_queries: false
        emit_interface: true
        emit_exact_table_names: false

3.5.3 Write SQL Queries

Create a file internal/db/queries.sql:

-- name: GetOrder :one
SELECT * FROM orders
WHERE id = $1 LIMIT 1;

-- name: ListOrders :many
SELECT * FROM orders
ORDER BY id;

-- name: CreateOrder :one
INSERT INTO orders (
  customer_id, status, total_amount
) VALUES (
  $1, $2, $3
)
RETURNING *;

-- name: UpdateOrder :one
UPDATE orders
SET status = $2, total_amount = $3, updated_at = CURRENT_TIMESTAMP
WHERE id = $1
RETURNING *;

-- name: DeleteOrder :exec
DELETE FROM orders
WHERE id = $1;

3.5.4 Generate Go Code

Add a new target to our Makefile:

generate-sqlc:
    @echo "Generating sqlc code..."
    sqlc generate

Run the code generation:

make generate-sqlc

This will generate Go code for interacting with our database in the internal/db directory.

3.6 Integrating Temporal

3.6.1 Set Up Temporal Server

Add Temporal to our docker-compose.yml:

  temporal:
    image: temporalio/auto-setup:1.13.0
    ports:
      - "7233:7233"
    environment:
      - DB=postgresql
      - DB_PORT=5432
      - POSTGRES_USER=orderuser
      - POSTGRES_PWD=orderpass
      - POSTGRES_SEEDS=postgres
    depends_on:
      - postgres

  temporal-admin-tools:
    image: temporalio/admin-tools:1.13.0
    depends_on:
      - temporal

3.6.2 Implement a Basic Workflow

Create a file internal/workflow/order_workflow.go:

package workflow

import (
    "time"

    "go.temporal.io/sdk/workflow"
    "github.com/yourusername/order-processing-system/internal/db"
)

func OrderWorkflow(ctx workflow.Context, order db.Order) error {
    logger := workflow.GetLogger(ctx)
    logger.Info("OrderWorkflow started", "OrderID", order.ID)

    // Simulate order processing
    err := workflow.Sleep(ctx, 5*time.Second)
    if err != nil {
        return err
    }

    // Update order status
    err = workflow.ExecuteActivity(ctx, UpdateOrderStatus, workflow.ActivityOptions{
        StartToCloseTimeout: time.Minute,
    }, order.ID, "completed").Get(ctx, nil)
    if err != nil {
        return err
    }

    logger.Info("OrderWorkflow completed", "OrderID", order.ID)
    return nil
}

func UpdateOrderStatus(ctx workflow.Context, orderID int64, status string) error {
    // TODO: Implement database update
    return nil
}

This basic workflow simulates order processing by waiting for 5 seconds and then updating the order status to “completed”.

3.6.3 Integrate Workflow with API

Update the internal/api/handler.go file to include Temporal client and start the workflow:

package api

import (
    "context"
    "net/http"

    "github.com/gin-gonic/gin"
    "go.temporal.io/sdk/client"
    "github.com/yourusername/order-processing-system/internal/db"
    "github.com/yourusername/order-processing-system/internal/workflow"
)

type Handler struct {
    queries *db.Queries
    temporalClient client.Client
}

func NewHandler(queries *db.Queries, temporalClient client.Client) *Handler {
    return &Handler{
        queries: queries,
        temporalClient: temporalClient,
    }
}

// ... (previous handler methods)

func (h *Handler) CreateOrder(c *gin.Context) {
    var req CreateOrderRequest
    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
        return
    }

    order, err := h.queries.CreateOrder(c, db.CreateOrderParams{
        CustomerID: req.CustomerId,
        Status: "pending",
        TotalAmount: req.TotalAmount,
    })
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
        return
    }

    // Start Temporal workflow
    workflowOptions := client.StartWorkflowOptions{
        ID: "order-" + order.ID,
        TaskQueue: "order-processing",
    }
    _, err = h.temporalClient.ExecuteWorkflow(context.Background(), workflowOptions, workflow.OrderWorkflow, order)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to start workflow"})
        return
    }

    c.JSON(http.StatusCreated, order)
}

// ... (implement other handler methods)

3.7 Implementing Dependency Injection

Create a new file internal/service/service.go:

package service

import (
    "database/sql"

    "github.com/yourusername/order-processing-system/internal/api"
    "github.com/yourusername/order-processing-system/internal/db"
    "go.temporal.io/sdk/client"
)

type Service struct {
    DB *sql.DB
    Queries *db.Queries
    TemporalClient client.Client
    Handler *api.Handler
}

func NewService() (*Service, error) {
    // Initialize database connection
    db, err := sql.Open("postgres", "postgresql://orderuser:orderpass@localhost:5432/orderdb?sslmode=disable")
    if err != nil {
        return nil, err
    }

    // Initialize Temporal client
    temporalClient, err := client.NewClient(client.Options{
        HostPort: "localhost:7233",
    })
    if err != nil {
        return nil, err
    }

    // Initialize queries
    queries := db.New(db)

    // Initialize handler
    handler := api.NewHandler(queries, temporalClient)

    return &Service{
        DB: db,
        Queries: queries,
        TemporalClient: temporalClient,
        Handler: handler,
    }, nil
}

func (s *Service) Close() {
    s.DB.Close()
    s.TemporalClient.Close()
}

3.8 Update Main Function

Update the cmd/api/main.go file:

package main

import (
    "log"

    "github.com/gin-gonic/gin"
    _ "github.com/lib/pq"
    "github.com/yourusername/order-processing-system/internal/service"
)

func main() {
    svc, err := service.NewService()
    if err != nil {
        log.Fatalf("Failed to initialize service: %v", err)
    }
    defer svc.Close()

    r := gin.Default()
    svc.Handler.RegisterRoutes(r)

    if err := r.Run(":8080"); err != nil {
        log.Fatalf("Failed to run server: %v", err)
    }
}

3.9 Dockerize the Application

Create a Dockerfile in the project root:

# Build stage
FROM golang:1.17-alpine AS build

WORKDIR /app

COPY go.mod go.sum ./
RUN go mod download

COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -o /order-processing-system ./cmd/api

# Run stage
FROM alpine:latest

WORKDIR /

COPY --from=build /order-processing-system /order-processing-system

EXPOSE 8080

ENTRYPOINT ["/order-processing-system"]

Update the docker-compose.yml file to include our application:

version: '3.8'

services:
  postgres:
    # ... (previous postgres configuration)

  temporal:
    # ... (previous temporal configuration)

  temporal-admin-tools:
    # ... (previous temporal-admin-tools configuration)

  app:
    build: .
    ports:
      - "8080:8080"
    depends_on:
      - postgres
      - temporal
    environment:
      - DB_HOST=postgres
      - DB_USER=orderuser
      - DB_PASSWORD=orderpass
      - DB_NAME=orderdb
      - TEMPORAL_HOST=temporal:7233

4. Code Examples with Detailed Comments

Throughout the implementation guide, we’ve provided code snippets with explanations. Here’s a more detailed look at a key part of our system: the Order Workflow.

package workflow

import (
    "time"

    "go.temporal.io/sdk/workflow"
    "github.com/yourusername/order-processing-system/internal/db"
)

// OrderWorkflow defines the workflow for processing an order
func OrderWorkflow(ctx workflow.Context, order db.Order) error {
    logger := workflow.GetLogger(ctx)
    logger.Info("OrderWorkflow started", "OrderID", order.ID)

    // Simulate order processing
    // In a real-world scenario, this could involve multiple activities such as
    // inventory check, payment processing, shipping arrangement, etc.
    err := workflow.Sleep(ctx, 5*time.Second)
    if err != nil {
        return err
    }

    // Update order status
    // We use ExecuteActivity to run the status update as an activity
    // This allows for automatic retries and error handling
    err = workflow.ExecuteActivity(ctx, UpdateOrderStatus, workflow.ActivityOptions{
        StartToCloseTimeout: time.Minute,
    }, order.ID, "completed").Get(ctx, nil)
    if err != nil {
        return err
    }

    logger.Info("OrderWorkflow completed", "OrderID", order.ID)
    return nil
}

// UpdateOrderStatus is an activity that updates the status of an order
func UpdateOrderStatus(ctx workflow.Context, orderID int64, status string) error {
    // TODO: Implement database update
    // In a real implementation, this would use the db.Queries to update the order status
    return nil
}

This workflow demonstrates several key concepts:

  1. Use of Temporal’s workflow.Context for managing the workflow lifecycle.
  2. Logging within workflows using workflow.GetLogger.
  3. Simulating long-running processes with workflow.Sleep.
  4. Executing activities within a workflow using workflow.ExecuteActivity.
  5. Handling errors and returning them to be managed by Temporal.

5. Testing and Validation

For this initial setup, we’ll focus on manual testing to ensure our system is working as expected. In future posts, we’ll dive into unit testing, integration testing, and end-to-end testing strategies.

To manually test our system:

  1. Start the services:
docker-compose up

  1. Use a tool like cURL or Postman to send requests to our API:

  2. Check the logs to ensure the Temporal workflow is being triggered and completed successfully.

6. Challenges and Considerations

While setting up this initial version of our order processing system, we encountered several challenges and considerations:

  1. Database Schema Design : Designing a flexible yet efficient schema for orders is crucial. We kept it simple for now, but in a real-world scenario, we might need to consider additional tables for order items, customer information, etc.

  2. Error Handling : Our current implementation has basic error handling. In a production system, we’d need more robust error handling and logging, especially for the Temporal workflows.

  3. Configuration Management : We hardcoded configuration values for simplicity. In a real-world scenario, we’d use environment variables or a configuration management system.

  4. Keselamatan : Persediaan semasa kami tidak termasuk sebarang pengesahan atau kebenaran. Dalam sistem pengeluaran, kami perlu melaksanakan langkah keselamatan yang betul.

  5. Skalabiliti : Walaupun Temporal membantu dengan kebolehskalaan aliran kerja, kami perlu mempertimbangkan kebolehskalaan pangkalan data dan prestasi API untuk sistem trafik tinggi.

  6. Pemantauan dan Kebolehmerhatian : Kami belum melaksanakan sebarang alat pemantauan atau kebolehmerhatian lagi. Dalam sistem pengeluaran, ini akan menjadi penting untuk menyelenggara dan menyelesaikan masalah aplikasi.

7. Langkah Seterusnya dan Pratonton Bahagian 2

Dalam bahagian pertama siri kami ini, kami telah menyediakan asas untuk sistem pemprosesan pesanan kami. Kami mempunyai API CRUD asas, penyepaduan pangkalan data dan aliran kerja Temporal yang ringkas.

Dalam bahagian seterusnya, kita akan menyelami lebih mendalam aliran kerja dan aktiviti Temporal. Kami akan meneroka:

  1. Melaksanakan logik pemprosesan pesanan yang lebih kompleks
  2. Mengendalikan aliran kerja yang berjalan lama dengan Temporal
  3. Melaksanakan logik cuba semula dan pengendalian ralat dalam aliran kerja
  4. Mengubah versi aliran kerja untuk kemas kini yang selamat
  5. Melaksanakan corak saga untuk transaksi yang diedarkan
  6. Pemantauan dan pemerhatian untuk aliran kerja Temporal

Kami juga akan mula menyempurnakan API kami dengan logik pemprosesan pesanan yang lebih realistik dan meneroka corak untuk mengekalkan kod yang bersih dan boleh diselenggara apabila sistem kami semakin kompleks.

Nantikan Bahagian 2, di mana kami akan membawa sistem pemprosesan pesanan kami ke peringkat seterusnya!


Perlukan Bantuan?

Adakah anda menghadapi masalah yang mencabar, atau memerlukan perspektif luaran tentang idea atau projek baharu? Saya boleh tolong! Sama ada anda ingin membina konsep bukti teknologi sebelum membuat pelaburan yang lebih besar, atau anda memerlukan panduan tentang isu yang sukar, saya sedia membantu.

Perkhidmatan yang Ditawarkan:

  • Penyelesaian Masalah: Menangani isu yang rumit dengan penyelesaian yang inovatif.
  • Perundingan: Memberikan nasihat pakar dan pandangan baharu tentang projek anda.
  • Bukti Konsep: Membangunkan model awal untuk menguji dan mengesahkan idea anda.

Jika anda berminat untuk bekerja dengan saya, sila hubungi melalui e-mel di hungaikevin@gmail.com.

Mari jadikan cabaran anda sebagai peluang!

위 내용은 주문 처리 시스템 구현: 기반 구축 부분의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
GO의 문자열 조작 : '문자열'패키지 마스터 링GO의 문자열 조작 : '문자열'패키지 마스터 링May 14, 2025 am 12:19 AM

GO 언어로 문자열 패키지를 마스터하면 텍스트 처리 기능과 개발 효율성이 향상 될 수 있습니다. 1) 함유 기능을 사용하여 하위 문자열을 확인하십시오. 2) 인덱스 기능을 사용하여 하위 문자열 위치를 찾으십시오. 빈 문자열을 확인하지 않고 큰 문자열 작동 성능 문제와 같은 일반적인 오류를 피하기 위해주의하십시오.

'문자열'패키지 팁과 요령으로 이동하십시오'문자열'패키지 팁과 요령으로 이동하십시오May 14, 2025 am 12:18 AM

문자열 조작을 단순화하고 코드를보다 명확하고 효율적으로 만들 수 있기 때문에 이동중인 문자열 패키지에주의해야합니다. 1) strings.join을 사용하여 줄을 효율적으로 스플 라이스; 2) strings.fields를 사용하여 빈 문자로 문자열을 나눕니다. 3) 문자열을 통해 기판 위치를 찾으십시오. 4) 문자열을 대체하려면 strings.replaceall을 사용하십시오. 5) 현악기를 효율적으로 스플 라이스로 사용하여 strings.builder를 사용하십시오. 6) 예상치 못한 결과를 피하기 위해 항상 입력을 확인하십시오.

'문자열'패키지의 이동 : 문자열 작업을위한 이동'문자열'패키지의 이동 : 문자열 작업을위한 이동May 14, 2025 am 12:17 AM

thestringspackageoisessentialponderfficientstringmanipulation.1) itofferssimpleyetpowerfultionsfortaskslikecheckingsubstringsandjoiningstrings.2) ithandlesunicodewell, withFunctionsLikestrings.fieldsforwhitespace-separatedValues.3) forperformance, st

바이트 패키지 대 스트링 패키지로 이동하십시오 : 어떤 사용해야합니까?바이트 패키지 대 스트링 패키지로 이동하십시오 : 어떤 사용해야합니까?May 14, 2025 am 12:12 AM

whendecidingbetweengo'sbytespackageandstringspackage, usebytes.bufferforbinarydataandstrings.builderfortringoperations.1) audeBytes.bufferforworkingwhithbyteslices, binarydata, 첨부 DifferentDatatypes, andwritingtoio.2) useastrons

'문자열'패키지를 사용하여 단계별로 문자열을 조작하는 방법'문자열'패키지를 사용하여 단계별로 문자열을 조작하는 방법May 13, 2025 am 12:12 AM

GO의 문자열 패키지는 다양한 문자열 조작 기능을 제공합니다. 1) 문자열을 사용하여 기판을 확인하십시오. 2) strings.split을 사용하여 문자열을 서브 스트링 슬라이스로 분할하십시오. 3) 문자열을 통해 문자열을 병합합니다. 4) 문자열의 시작과 끝에서 strings.trimspace 또는 strings.trim을 사용하여 공백 또는 지정된 문자를 제거하십시오. 5) 지정된 모든 하위 문구를 문자열로 교체하십시오. 6) strings.hasprefix 또는 strings.hassuffix를 사용하여 문자열의 접두사 또는 접미사를 확인하십시오.

Go Strings 패키지 : 코드를 개선하는 방법?Go Strings 패키지 : 코드를 개선하는 방법?May 13, 2025 am 12:10 AM

Go Language Strings 패키지를 사용하면 코드 품질이 향상 될 수 있습니다. 1) strings.join ()을 사용하여 성능 오버 헤드를 피하기 위해 문자열 배열을 우아하게 연결하십시오. 2) strings.split () 및 strings.contains ()를 결합하여 텍스트를 처리하고 사례 민감도 문제에주의를 기울입니다. 3) 문자열의 남용을 피하고 ()을 replace ()하고 많은 수의 대체에 정규 표현식을 사용하는 것을 고려하십시오. 4) strings.builder를 사용하여 자주 스 플라이 싱 스트링의 성능을 향상시킵니다.

Go Bytes 패키지에서 가장 유용한 기능은 무엇입니까?Go Bytes 패키지에서 가장 유용한 기능은 무엇입니까?May 13, 2025 am 12:09 AM

GO의 바이트 패키지는 바이트 슬라이싱을 처리하기위한 다양한 실용적인 기능을 제공합니다. 1. BYTES는 바이트 슬라이스에 특정 시퀀스가 ​​포함되어 있는지 확인하는 데 사용됩니다. 2.Bytes.split은 바이트 슬라이스를 작은 피스로 분할하는 데 사용됩니다. 3.Bytes.join은 여러 바이트 슬라이스를 하나로 연결하는 데 사용됩니다. 4.bytes.trimspace는 바이트 슬라이스의 전면 및 후면 블랭크를 제거하는 데 사용됩니다. 5.Bytes.equal은 두 바이트 슬라이스가 동일인지 비교하는 데 사용됩니다. 6.bytes.index는 LargersLices에서 하위 슬라이스의 시작 지수를 찾는 데 사용됩니다.

GO의 '인코딩/바이너리'패키지로 바이너리 데이터 처리 마스터 링 : 포괄적 인 가이드GO의 '인코딩/바이너리'패키지로 바이너리 데이터 처리 마스터 링 : 포괄적 인 가이드May 13, 2025 am 12:07 AM

Theencoding/BinaryPackageInsentialBecauseItProvideAstandAdizedWayStandwriteBinaryData, Cross-PlatformCompatibility 및 HandshandlingDifferentendianness.ItoffersFunctionsLikeRead, Write, andwriteUvarIntForPrecisControloverbinary

See all articles

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

Video Face Swap

Video Face Swap

완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

뜨거운 도구

안전한 시험 브라우저

안전한 시험 브라우저

안전한 시험 브라우저는 온라인 시험을 안전하게 치르기 위한 보안 브라우저 환경입니다. 이 소프트웨어는 모든 컴퓨터를 안전한 워크스테이션으로 바꿔줍니다. 이는 모든 유틸리티에 대한 액세스를 제어하고 학생들이 승인되지 않은 리소스를 사용하는 것을 방지합니다.

DVWA

DVWA

DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

VSCode Windows 64비트 다운로드

VSCode Windows 64비트 다운로드

Microsoft에서 출시한 강력한 무료 IDE 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)