Réflexion d'un psychorigide quant à l'usage des chaînes de caractères

J’ai toujours été frileux concernant les chaînes de caractères utilisées comme clés ou identifiants… Peut-être de vieux traumatismes liés à d’anciennes expériences en C ou C++, qui sait…

Ceci étant, une des raisons pour laquelle j’apprécie vraiment le Swift c’est bien pour son typage fort et sa grande versatilité dans l’usage des types énumérés. Ceci étant dit, on ne peut pas toujours passer par là, et c’est donc ici que se pose ma réflexion :

En plein développement d’un petit projet Vapor avec Fluent, j’ai suivi l’usage utilisé dans le projet de démo. Mais de trouver à 3 endroits différents du projet le nom du schéma en chaîne de caractères "todos" m’a fait un peu bondir… Pareil, avec les noms des champs, que l’on retrouve dans le modèle et dans la migration mais aussi au fil des routes dans les différentes requêtes…

Alors je comprends bien que c’est un projet d’exemple pas du code de production, mais étant adepte du concept DRY (Don’t Repeat Yourself) ça me gratouille la cornée à chaque fois que je vois ça !

Du coup, j’ai opté pour une solution simple et un peu moins error-prone à mes yeux, je me permets de vous la proposer ici. J’utilise simplement une structure avec des constantes statiques qui vont me servir tout le long du projet :

struct RecordSchema {
    static let schemaName = "records"
    
    // MARK:- Fields
    static let date : FieldKey = "date"
    static let count : FieldKey = "count"
}

Ainsi, voici à quoi ressemble ma migration :

struct CreateCountRecord: Migration {
    func prepare(on database: Database) -> EventLoopFuture<Void> {
        database.schema(RecordSchema.schemaName)
            .id()
            .field(RecordSchema.date, .datetime, .required)
            .field(RecordSchema.count, .uint, .required)
            .create()
    }
    
    func revert(on database: Database) -> EventLoopFuture<Void> {
        database.schema(RecordSchema.schemaName).delete()
    }
}

Et mon modèle :

final class CountRecord: Model, Content {
    static let schema = RecordSchema.schemaName
    
    @ID(key: .id)
    var id: UUID?

    @Field(key: RecordSchema.date)
    var date: Date

    @Field(key: RecordSchema.count)
    var count: UInt

    ... 
}

Ça permet aussi de faire les choses bien, par exemple dans les requêtes :

.filter(RecordSchema.date, .greaterThanOrEqual, interval.start)
.filter(RecordSchema.date, .lessThanOrEqual, interval.end)

Voilà, c’était juste une réflexion en passant, qu’en pensez-vous ? C’est overkill et il n’y en a pas besoin : stringz rulez ? C’était évident, tout le monde fait comme ça, pas besoin d’en faire une tartine ? Et vous vous faites comment ?

3 J'aime

J’ai la même approche. Je déteste les constantes de chaînes de caractères, où il est tellement facile de se tromper. J’ai eu quelques expériences malheureuses dans le passé, avec ce système.

2 J'aime

C’est une excellente habitude et je suis tout à fait d’accord avec toi sur le besoin.
Sur la réalisation, tu peux faire encore plus simple en utilisant une énumération qui hériterait de String :

enum RecordSchema : String {
    case schemaName = "records"
    
    // MARK:- Fields
    case date
    case count
}

@mbritto c’est ce que j’avais commencé à faire, mais le souci c’est que pour accéder à la chaine de caractères, tu vas devoir faire : RecordSchema.schemaName.rawValue ce qui rallonge un peu, mais surtout, pour les champs, ça ne va pas fonctionner. Car ils attendent des FieldKey ou des littéraux de chaînes.

Donc soit tu fais : FieldKey(stringLiteral: RecordSchema.date.rawValue) qui n’est plus trop lisible.

Soit tu rajoutes une extension du genre :

extension RawRepresentable where RawValue == String {
    var field : FieldKey { FieldKey(stringLiteral: self.rawValue) } 
}

Pour finir par faire RecordSchema.date.field.

À moins que tu aies une autre façon ?

Effectivement, avec cette contrainte la struct que tu as proposé au départ semble plus simple.

1 J'aime

Deja un vieux post mais j’ai pris l’habitude de faire pareil.
Je pense que prendre de bonnes habitudes dès le début permet de gagner beaucoup de temps, surtout en débogage !

1 J'aime