Votre code est-il aussi agile que votre projet ?

Artisan développeur

Benoit Sautel

Un cas unique dans l'industrie

Immatériel

Vous avez dit agile ?

Itérer - Essayer - Ajuster
Rectifier - Renoncer

Notre code est-il adapté à ces contraintes ?

Comment faire ?

Produire du code malléable

Choisir de ne pas choisir

Limiter le couplage

Abstraire quand c'est pertinent


public interface UsersRepository
        extends MongoRepository<User, UUID> {
    Optional<User> findById(UUID id);

    User save(User user);

    List<User> findByEmailAddress(String emailAddress);
}
               

public class User {
    @Id
    private final UUID id;
    private final String firstName;
    private final String lastName;
    @Indexed
    private final String emailAddress;
}
                

public class MongoDbUser {
    @Id
    private final UUID id;
    private final String firstName;
    private final String lastName;
    @Indexed
    private final String emailAddress;

    public User toUser() {
        return new User(id, firstName, lastName, emailAddress);
    }
}
                

public interface MongoDbUsersRepository
        extends MongoRepository<MongoDbUser, UUID> {
    Optional<MongoDbUser> findById(UUID id);

    MongoDbUser save(MongoDbUser user);

    List<MongoDbUser> findByEmailAddress(String emailAddress);
}
                

public class User {
    private final UUID id;
    private final String firstName;
    private final String lastName;
    private final String emailAddress;
}
                

public class UsersRepository {
    private final MongoDbUsersRepository mongoDbUsersRepository;

    public UsersRepository(MongoDbUsersRepository mongoDbUsersRepository) {
        this.mongoDbUsersRepository = mongoDbUsersRepository;
    }

    public List<User> findByEmailAddress(String emailAddress) {
        return mongoDbUsersRepository.findByEmailAddress(emailAddress)
                .stream()
                .map(MongoDbUser::toUser)
                .collect(toList());
    }
}
                

Découpage modulaire

Retour aux fondamentaux

SOLID

Principe de responsabilité unique

SRP - Single Responsibility Principle


public class User {
    private final UUID id;
    private final String firstName;
    private final String lastName;
    private final String emailAddress;

    public String toJson() {
        return "{\"id\":\"" + id + "\",[...]}";
    }
}
                

public class User {
    private final UUID id;
    private final String firstName;
    private final String lastName;
    private final String emailAddress;
}

public class UserJsonSerializer {
    public static String serializeToJson(User user) {
        return "{\"id\":\"" + user.getId() + "\",[...]}";
    }
}
                

4ffb288d-6444-49f1-bc50-c9c7ac772757;Bob;Martin;bob@cleancode.com
18705afe-f896-46b6-b157-6b33a3efb189;Alice;Martin;alice@badcode.com
                

public class UsersReader {
    public List<User> readUsers(Path usersFilePath)
            throws IOException {
        byte[] binaryFileContents = Files.readAllBytes(usersFilePath);
        String fileContents = new String(binaryFileContents, UTF_8);
        return Stream.of(fileContents.split("\n"))
                .map(line -> {
                    String[] lineParts = line.split(";");
                    return new User(UUID.fromString(lineParts[0]),
                        lineParts[1], lineParts[2], lineParts[3]);
                })
                .collect(toList());
    }
}
                

public class FileContentsReader {
    public String readFile(Path filePath) throws IOException {
        byte[] binaryFileContents = Files.readAllBytes(filePath);
        return new String(binaryFileContents, UTF_8);
    }
}
                

public class StringLinesReader {
    public String[] readLines(String value) {
        return value.split("\n");
    }
}
                

public class UserLineReader {
    public User readUser(String line) {
        String[] lineParts = line.split(";");
        return new User(UUID.fromString(lineParts[0]),
                    lineParts[1], lineParts[2], lineParts[3]);
    }
}
                

public class UsersReader {
    private final FileContentsReader fileContentsReader =
            new FileContentsReader();
    private final StringLinesReader stringLinesReader =
            new StringLinesReader();
    private final UserLineReader userLineReader =
            new UserLineReader();

    public List<User> readUsers(Path usersFilePath)
            throws IOException {
        String fileContents =
                fileContentsReader.readFile(usersFilePath);
        String[] lines =
                stringLinesReader.readLines(fileContents);
        return Stream.of(lines)
                .map(userLineReader::readUser)
                .collect(toList());
    }
}
                

On gagne sur beaucoup de terrains

Inversion des dépendances


public class UsersReader {
    private final FileContentsReader fileContentsReader;
    private final StringLinesReader stringLinesReader;
    private final UserLineReader userLineReader;

    public UsersReader(FileContentsReader fileContentsReader,
                    StringLinesReader stringLinesReader,
                    UserLineReader userLineReader) {
        this.fileContentsReader = fileContentsReader;
        this.stringLinesReader = stringLinesReader;
        this.userLineReader = userLineReader;
    }

    public List<User> readUsers(Path usersFilePath)
                    throws IOException {
        String fileContents =
                fileContentsReader.readFile(usersFilePath);
        String[] lines =
                stringLinesReader.readLines(fileContents);
        return Stream.of(lines)
                .map(userLineReader::readUser)
                .collect(toList());
    }
}
                

Automatiser

Tester son code

Tests de non régression

Gain d'efficacité

Tester ça s'apprend

Bonnes pratiques de conception

Vélocité constante

Retour d'expérience

Conseil de lecture

Clean Code de Robert C. Martin (Uncle Bob)

The only way to go fast is to go well!

Des questions ?

www.fierdecoder.fr