Latviešu

Uzziniet, kā heksagonālā arhitektūra, pazīstama arī kā porti un adapteri, var uzlabot jūsu lietojumprogrammu uzturēšanu, testēšanu un elastību. Šis ceļvedis sniedz praktiskus piemērus un noderīgas atziņas izstrādātājiem visā pasaulē.

Heksagonālā arhitektūra: praktisks portu un adapteru ceļvedis

Nepārtraukti mainīgajā programmatūras izstrādes ainavā robustu, uzturamu un testējamu lietojumprogrammu veidošana ir vissvarīgākā. Heksagonālā arhitektūra, pazīstama arī kā porti un adapteri, ir arhitektūras šablons, kas risina šīs problēmas, atsaistot lietojumprogrammas galveno biznesa loģiku no tās ārējām atkarībām. Šī ceļveža mērķis ir sniegt visaptverošu izpratni par heksagonālo arhitektūru, tās priekšrocībām un praktiskām ieviešanas stratēģijām izstrādātājiem visā pasaulē.

Kas ir heksagonālā arhitektūra?

Heksagonālā arhitektūra, ko ieviesa Alisters Kokberns (Alistair Cockburn), balstās uz ideju izolēt lietojumprogrammas galveno biznesa loģiku no ārējās pasaules. Šī izolācija tiek panākta, izmantojot portus un adapterus.

Iedomājieties to šādi: lietojumprogrammas kodols atrodas centrā, ko apņem heksagonāls apvalks. Porti ir ieejas un izejas punkti uz šī apvalka, un adapteri pieslēdzas šiem portiem, savienojot kodolu ar ārējo pasauli.

Heksagonālās arhitektūras galvenie principi

Vairāki galvenie principi ir pamatā heksagonālās arhitektūras efektivitātei:

Heksagonālās arhitektūras izmantošanas priekšrocības

Heksagonālās arhitektūras pieņemšana piedāvā daudzas priekšrocības:

Heksagonālās arhitektūras ieviešana: praktisks piemērs

Ilustrēsim heksagonālās arhitektūras ieviešanu ar vienkāršotu lietotāja reģistrācijas sistēmas piemēru. Skaidrības labad izmantosim hipotētisku programmēšanas valodu (līdzīgu Java vai C#).

1. Definējiet kodolu (lietojumprogrammu)

Lietojumprogrammas kodols satur biznesa loģiku jauna lietotāja reģistrēšanai.


// Core/UserService.java (or UserService.cs)
public class UserService {
    private final UserRepository userRepository;
    private final PasswordHasher passwordHasher;
    private final UserValidator userValidator;

    public UserService(UserRepository userRepository, PasswordHasher passwordHasher, UserValidator userValidator) {
        this.userRepository = userRepository;
        this.passwordHasher = passwordHasher;
        this.userValidator = userValidator;
    }

    public Result<User, String> registerUser(String username, String password, String email) {
        // Validate user input
        ValidationResult validationResult = userValidator.validate(username, password, email);
        if (!validationResult.isValid()) {
            return Result.failure(validationResult.getErrorMessage());
        }

        // Check if user already exists
        if (userRepository.findByUsername(username).isPresent()) {
            return Result.failure("Username already exists");
        }

        // Hash the password
        String hashedPassword = passwordHasher.hash(password);

        // Create a new user
        User user = new User(username, hashedPassword, email);

        // Save the user to the repository
        userRepository.save(user);

        return Result.success(user);
    }
}

2. Definējiet portus

Mēs definējam portus, ko lietojumprogrammas kodols izmanto, lai mijiedarbotos ar ārējo pasauli.


// Ports/UserRepository.java (or UserRepository.cs)
public interface UserRepository {
    Optional<User> findByUsername(String username);
    void save(User user);
}

// Ports/PasswordHasher.java (or PasswordHasher.cs)
public interface PasswordHasher {
    String hash(String password);
}

//Ports/UserValidator.java (or UserValidator.cs)
public interface UserValidator{
  ValidationResult validate(String username, String password, String email);
}

//Ports/ValidationResult.java (or ValidationResult.cs)
public interface ValidationResult{
  boolean isValid();
  String getErrorMessage();
}

3. Definējiet adapterus

Mēs ieviešam adapterus, kas savieno lietojumprogrammas kodolu ar konkrētām tehnoloģijām.


// Adapters/DatabaseUserRepository.java (or DatabaseUserRepository.cs)
public class DatabaseUserRepository implements UserRepository {
    private final DatabaseConnection databaseConnection;

    public DatabaseUserRepository(DatabaseConnection databaseConnection) {
        this.databaseConnection = databaseConnection;
    }

    @Override
    public Optional<User> findByUsername(String username) {
        // Implementation using JDBC, JPA, or another database access technology
        // ...
        return Optional.empty(); // Placeholder
    }

    @Override
    public void save(User user) {
        // Implementation using JDBC, JPA, or another database access technology
        // ...
    }
}

// Adapters/BCryptPasswordHasher.java (or BCryptPasswordHasher.cs)
public class BCryptPasswordHasher implements PasswordHasher {
    @Override
    public String hash(String password) {
        // Implementation using BCrypt library
        // ...
        return "hashedPassword"; //Placeholder
    }
}

//Adapters/SimpleUserValidator.java (or SimpleUserValidator.cs)
public class SimpleUserValidator implements UserValidator {
  @Override
  public ValidationResult validate(String username, String password, String email){
    //Simple Validation logic
     if (username == null || username.isEmpty()) {
            return new SimpleValidationResult(false, "Username cannot be empty");
        }
        if (password == null || password.length() < 8) {
            return new SimpleValidationResult(false, "Password must be at least 8 characters long");
        }
        if (email == null || !email.contains("@")) {
            return new SimpleValidationResult(false, "Invalid email format");
        }

        return new SimpleValidationResult(true, null);
  }
}

//Adapters/SimpleValidationResult.java (or SimpleValidationResult.cs)
public class SimpleValidationResult implements ValidationResult {
  private final boolean valid;
  private final String errorMessage;

    public SimpleValidationResult(boolean valid, String errorMessage) {
        this.valid = valid;
        this.errorMessage = errorMessage;
    }
  @Override
  public boolean isValid(){
    return valid;
  }

  @Override
  public String getErrorMessage(){
    return errorMessage;
  }
}



//Adapters/WebUserController.java (or WebUserController.cs)
//Driving Adapter - handles requests from the web
public class WebUserController {
    private final UserService userService;

    public WebUserController(UserService userService) {
        this.userService = userService;
    }

    public String registerUser(String username, String password, String email) {
        Result<User, String> result = userService.registerUser(username, password, email);
        if (result.isSuccess()) {
            return "Registration successful!";
        } else {
            return "Registration failed: " + result.getFailure();
        }
    }
}


4. Kompozīcija

Visa savienošana kopā. Ņemiet vērā, ka šī kompozīcija (atkarību injekcija) parasti notiek lietojumprogrammas ieejas punktā vai atkarību injekcijas konteinerā.


//Main class or dependency injection configuration
public class Main {
    public static void main(String[] args) {
        // Create instances of the adapters
        DatabaseConnection databaseConnection = new DatabaseConnection("jdbc:mydb://localhost:5432/users", "user", "password");
        DatabaseUserRepository userRepository = new DatabaseUserRepository(databaseConnection);
        BCryptPasswordHasher passwordHasher = new BCryptPasswordHasher();
        SimpleUserValidator userValidator = new SimpleUserValidator();

        // Create an instance of the core application, injecting the adapters
        UserService userService = new UserService(userRepository, passwordHasher, userValidator);

        //Create a driving adapter and connect it to the service
        WebUserController userController = new WebUserController(userService);

        //Now you can handle user registration requests through the userController
        String result = userController.registerUser("john.doe", "P@sswOrd123", "john.doe@example.com");
        System.out.println(result);
    }
}



//DatabaseConnection is a simple class for demonstration purposes only
class DatabaseConnection {
    private String url;
    private String username;
    private String password;

    public DatabaseConnection(String url, String username, String password) {
        this.url = url;
        this.username = username;
        this.password = password;
    }

    // ... methods to connect to the database (not implemented for brevity)
}

//Result class (similar to Either in functional programming)
class Result<T, E> {
    private final T success;
    private final E failure;
    private final boolean isSuccess;

    private Result(T success, E failure, boolean isSuccess) {
        this.success = success;
        this.failure = failure;
        this.isSuccess = isSuccess;
    }

    public static <T, E> Result<T, E> success(T value) {
        return new Result<>(value, null, true);
    }

    public static <T, E> Result<T, E> failure(E error) {
        return new Result<>(null, error, false);
    }

    public boolean isSuccess() {
        return isSuccess;
    }

    public T getSuccess() {
        if (!isSuccess) {
            throw new IllegalStateException("Result is a failure");
        }
        return success;
    }

    public E getFailure() {
        if (isSuccess) {
            throw new IllegalStateException("Result is a success");
        }
        return failure;
    }
}

class User {
    private String username;
    private String password;
    private String email;

    public User(String username, String password, String email) {
        this.username = username;
        this.password = password;
        this.email = email;
    }

    // getters and setters (omitted for brevity)

}

Paskaidrojums:

Padziļināti apsvērumi un labākā prakse

Lai gan heksagonālās arhitektūras pamatprincipi ir vienkārši, ir daži padziļināti apsvērumi, kas jāņem vērā:

Heksagonālās arhitektūras reālās pasaules piemēri

Daudzi veiksmīgi uzņēmumi un projekti ir pieņēmuši heksagonālo arhitektūru, lai izveidotu robustas un uzturamas sistēmas:

Izaicinājumi un kompromisi

Lai gan heksagonālā arhitektūra piedāvā ievērojamas priekšrocības, ir svarīgi apzināties ar to saistītos izaicinājumus un kompromisus:

Ir ļoti svarīgi rūpīgi izvērtēt heksagonālās arhitektūras priekšrocības un izaicinājumus jūsu konkrētā projekta prasību un komandas spēju kontekstā. Tā nav brīnumlīdzeklis, un tā var nebūt labākā izvēle katram projektam.

Noslēgums

Heksagonālā arhitektūra, ar tās uzsvaru uz portiem un adapteriem, nodrošina jaudīgu pieeju uzturamu, testējamu un elastīgu lietojumprogrammu veidošanai. Atsaistot galveno biznesa loģiku no ārējām atkarībām, tā ļauj viegli pielāgoties mainīgām tehnoloģijām un prasībām. Lai gan ir jāņem vērā izaicinājumi un kompromisi, heksagonālās arhitektūras priekšrocības bieži vien atsver izmaksas, īpaši sarežģītām un ilgtermiņa lietojumprogrammām. Pieņemot atkarību inversijas un skaidri definētu saskarņu principus, jūs varat izveidot sistēmas, kas ir noturīgākas, vieglāk saprotamas un labāk aprīkotas, lai atbilstu mūsdienu programmatūras ainavas prasībām.

Šis ceļvedis ir sniedzis visaptverošu pārskatu par heksagonālo arhitektūru, sākot no tās pamatprincipiem līdz praktiskām ieviešanas stratēģijām. Mēs aicinām jūs turpināt pētīt šos jēdzienus un eksperimentēt, pielietojot tos savos projektos. Ieguldījums heksagonālās arhitektūras apguvē un pieņemšanā neapšaubāmi atmaksāsies ilgtermiņā, nodrošinot augstākas kvalitātes programmatūru un apmierinātākas izstrādes komandas.

Galu galā pareizās arhitektūras izvēle ir atkarīga no jūsu projekta specifiskajām vajadzībām. Pieņemot lēmumu, apsveriet sarežģītības, ilgmūžības un uzturēšanas prasības. Heksagonālā arhitektūra nodrošina stabilu pamatu robustu un pielāgojamu lietojumprogrammu veidošanai, taču tas ir tikai viens rīks programmatūras arhitekta rīku komplektā.