La logica della mutazione del flusso deve sempre essere eseguita nell'archivio o può essere delegata a una classe?

1

(Sto usando Vuex ma la domanda si applica a qualsiasi architettura di Flux.)

Non ho una grande comprensione del ragionamento che sta dietro all'architettura Flux. Capisco che è bello avere tutto lo stato in un posto. Però non ho una grande conoscenza di altre cose.

La mia domanda qui è su dove, esattamente, dovrebbe essere la logica di mutazione. Ho l'impressione che l'architettura di Flux voglia che tu abbia tutta la logica della mutazione in un unico posto - il negozio - perché ti dà una buona separazione di preoccupazioni. Vale a dire. quando vuoi sapere dove si trova la logica delle mutazioni, sai dove cercare.

Ma trovo che sia bello avere delle classi e usare i metodi di istanza per gestire il cambiamento di stato. Penso che user.computeAndSetKarma() appaia molto più bello di storeHelper.computeAndSetKarmaForUser(user) . Robert Martin ne parla nel suo libro Clean Code :

A function with two arguments is harder to understand than a monadic function. For example, writeField(name) is easier to understand than writeField(output-Stream, name). Though the meaning of both is clear, the first glides past the eye, easily depositing its meaning. The second requires a short pause until we learn to ignore the first parameter. And that, of course, eventually results in problems because we should never ignore any part of code. The parts we ignore are where the bugs will hide.

...

Dyads aren’t evil, and you will certainly have to write them. However, you should be aware that they come at a cost and should take advantage of what mechanims may be available to you to convert them into monads. For example, you might make the writeField method a member of outputStream so that you can say outputStream.writeField(name). Or you might make the outputStream a member variable of the current class so that you don’t have to pass it. Or you might extract a new class like FieldWriter that takes the outputStream in its constructor and has a write method.

Considera questo esempio ( CodePen ):

HTML

<div id="app">
  <table class="table">
     <thead>
       <tr>
         <th>Name</th>
         <th>Karma</th>
         <th>Compute karma (with logic done in store)</th>
         <th>Compute karma (with logic delegated to user)</th>
       </tr>
    </thead>
    <tbody>
      <tr v-for="(user, userIndex) in users">
        <td>{{ user.name }}</td>
        <td>{{ user.karma }}</td>
        <td>
          <button v-on:click="computeKarmaWithLogicDoneInStore(userIndex)">
            Compute
          </button>      
        </td>
        <td>
          <button v-on:click="computeKarmaWithLogicDelegatedToClass(user)">
            Compute
          </button>      
        </td>
      </tr>
    </tbody>
  </table>
</div>
<script src="https://cdn.jsdelivr.net/g/[email protected],[email protected]"></script>

JS

class User {
  constructor (name) {
    this.name = name;
    this.karma = 0;
    this.posts = [];
    this.comments = [];
  };

  computeAndSetNewKarma() {
    let postQualityScore = this._getPostQualityScore();
    let commentQualityScore = this._getCommentQualityScore();
    let activityScore = this._getActivityScore();
    let newKarma = this._getKarma(
      postQualityScore, 
      commentQualityScore, 
      activityScore
    );

    this.karma = newKarma;
  };

  _getPostQualityScore() {
    return 5;
  };
  _getCommentQualityScore() {
    return 10;
  };
  _getActivityScore() {
    return 15;
  };
  _getKarma(postQualityScore, commentQualityScore, activityScore) {
    return postQualityScore + commentQualityScore + activityScore;
  };
}

const storeHelper = {
  getPostQualityScore: function (posts) {
    return 5;
  },
  getCommentQualityScore: function (comments) {
    return 10;
  },
  getActivityScore: function (posts, comments) {
    return 15;
  },
  getKarma: function (postQualityScore, commentQualityScore, activityScore) {
    return postQualityScore + commentQualityScore + activityScore;
  },
};

const store = new Vuex.Store({
  state: {
    users: [
      new User('Adam'),
      new User('Bob'),
    ],
  },
  mutations: {
    computeKarmaWithLogicDoneInStore: function (state, userIndex) {
      let user = state.users[userIndex];
      let newPostQualityScore = storeHelper.getPostQualityScore(user.posts);
      let newCommentQualityScore = storeHelper.getCommentQualityScore(user.comments);
      let newActivityScore = storeHelper.getActivityScore(user.posts, user.comments);
      let newKarma = storeHelper.getKarma(
        newPostQualityScore, 
        newCommentQualityScore, 
        newActivityScore
      );

      user.karma = newKarma;
    },
    computeKarmaWithLogicDelegatedToClass: function (state, user) {
      user.computeAndSetNewKarma();
    },
  },
});

new Vue({
  store: store,
  el: '#app',
  computed: {
    users: function () {
      return this.$store.state.users;
    },
  },
  methods: {
    computeKarmaWithLogicDoneInStore: function (userIndex) {
      this.$store.commit('computeKarmaWithLogicDoneInStore', userIndex);
    },
    computeKarmaWithLogicDelegatedToClass: function (user) {
      this.$store.commit('computeKarmaWithLogicDelegatedToClass', user);
    },
  }
});

Potresti eseguire la logica all'interno della mutazione, oppure puoi chiamare user.computeAndSetNewKarma() all'interno della mutazione, delegando la logica al metodo di istanza degli utenti. Quest'ultima sembra preferibile a me, ma non sono sicuro che questo violi le convenzioni, e non sono sicuro di pensarci correttamente.

    
posta Adam Zerner 08.06.2018 - 00:43
fonte

0 risposte

Leggi altre domande sui tag