JeuWeb - Crée ton jeu par navigateur
Compass : East Oriented - Version imprimable

+- JeuWeb - Crée ton jeu par navigateur (https://jeuweb.org)
+-- Forum : Discussions, Aide, Ressources... (https://jeuweb.org/forumdisplay.php?fid=38)
+--- Forum : Programmation, infrastructure (https://jeuweb.org/forumdisplay.php?fid=51)
+--- Sujet : Compass : East Oriented (/showthread.php?tid=7165)

Pages : 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30


RE: Compass : East Oriented - srm - 10-04-2015

Concernant le clone il est dans le but d'avoir un Router immutable ce qui aide à limiter les comportements imprévus.


RE: Compass : East Oriented - srm - 24-04-2015

http://est-voyage.blogspot.fr/

j'essaye de faire un blog à ce sujet Smile


RE: Compass : East Oriented - Xenos - 24-04-2015

J'ai plusieurs objections; si tu y trouves des réponses (ou autres invalidation du problème), je suis preneur Smile Au besoin, poste les réponses sous forme d'article sur le blog, et lie-les ici (répondre à ces objections sur le blog le renforcera)

1) Verbosité
Le code devient effectivement très verbeux, ce qui compense le gain de souplesse de East (okay, c'est souple, mais bien plus complexe à maintenir).


2) Obfuscation (c'est clairement le plus problématique à mon sens)
Beaucoup de retours ne sont non plus explicites (on n'a pas de "return"), mais implicite. Le code a l'air parallélisable, mais en réalité, il ne l'est pas car si "return" n'apparait pas, la logique du code se repose quand même dessus. Exemple: if ($this->canDrinkAlcohol === true) attends implicitement que le résultat de $this->country->canUserDrinkAlcohol($this); ait eu lieu. Idem dans canUserDrinkAlcohol.


3) Plus de méthodes publiques
Le code passe de deux méthodes publiques (void User::drinkAlcohol() et bool Country::getMajority()) à 7 méthodes publiques. Je pense que le risque de cassure de contrat ("Si country change son type de retour pour la méthode getMajority, mon code est cassé.") est alors bien plus important.


4) Lourdeur des classes
D'instinct, vu qu'il faut ajouter des méthodes quand on ajoute des conditions (void User:ConfusedexAskedByCountry(Country)), le code ne sera pas d'une excellente extensibilité (il faudra les créer et altérer l'endroit où on les appelle; avant on altérait seulement la condition if); mais cela peut probablement se régler par des patterns type "liste de trucs à appeler dans canUserDrinkAlcohol").


5) Combinatoire
Au vu des noms de méthodes de User (sexAskedByCountry(Country), oldAskedByCountry(User)), on se prive de la combinatoire (le truc qui fait qu'avec 5 objets, on a 20 combinaisons différentes possibles) de l'orienté objet, ce qui va certainement entrainer beaucoup de réécriture de code: combien de méthodes faut-il ajouter si la possibilité de boire de l'alcool est également influencée par les fédérations (genre Country=France, Federation=Europe), par les maladies éventuelles du User, ou par la qualité des boissons de cette année?



Pour ma part, c'est plutôt la façon de voir les getters/setters qui pose problème en OO. Apparemment, pour certains (dont toi), c'est un moyen d'accéder, de façon sécurisée/contrôlée, aux propriétés internes de l'objet ("J'ai longtemps pensé qu'un getter c'était bien. Je me disais que c'était mieux que de laisser la propriété publique, on contrôle vraiment la donnée qui est accédée depuis l'extérieur."). Je trouve cette approche mauvaise: rien, dans le "contrat" publique d'une classe ne doit indiquer quelque chose de privé (d'interne) à la classe.
Considérer que les getters/setters sont des accès contrôlés aux propriétés privées fait fuiter l'existence de ces propriétés vers l'extérieur de la classe.

Je considère plutôt les getters comme des moyens d'interroger l'objet sur une donnée. L'objet répond par une donnée (ou par un autre objet), qui peut tout à fait venir des propriétés internes de la classe, d'une base de données, d'une propriété statique, ou d'une valeur aléatoire.

De même, je vois les setters comme un moyen d'informer l'objet sur un évènement précis, plutôt qu'un moyen de définir une de ses propriétés internes (ce qui, je répète, ferait fuiter la structure interne de la classe vers l'extérieur).

Du coup, dans le cas qui nous préoccupe, l'approche classique ne me dérange pas (au sens où getMajority() renvoie seulement l'âge de majorité, et non pas la valeur d'un private $majority). Toutefois, si l'extensibilité est importante, je coderai plutôt un Adapter:


class User
{
private $alcoholDrinkAllower;

/// or "setAlcoholDrinkAllower", but if "set" bothers you, name it another way
public function useAlcoholDrinkAllower(IAllower $allower) {
if (mt_rand(0, 100) < 50)
$this->alcoholDrinkAllower = $allower;
else
echo "I just don't want to use that allower.";
}

public function drinkAlcohol() {
if ($this->alcoholDrinkAllower === null)
echo "I drink a beer (without any acknowledgement)";
else if ($this->alcoholDrinkAllower->isAllowed())
echo "I drink a beer";
}

/// Same: you can call it "getAge()" if you want to
public function askAge() {
return $this->age;
}
}


class UserDrinkAllower implements IAllower {
private $user;
private $country;
private $beerQuality = 8;

public function isAllowed() {
return ($user->askAge() >= $country->askMajority() && $beerQuality > 5);
}
}


class Country
{
/// It's somehow the same as a getter, it's just a matter of naming
public function askMajority() {
return (int)file_get_contents("country.majority.txt");
}
}



Après, PHP n'a pas de typage pour les retours des fonctions (donc, c'est sûr, le typage peut changer sans prévenir). Trois Deux solutions à cela:

• Considérer un typage de retour dans la documentation, mais qui dans le code n'est pas explicite

/**
* @return int Age
*/
public function getAge() { ... }

• Considérer que le typage du retour est quelconque, et faire les casts nécessaires (un peu lourd, mais le plus proche du langage)

public function isAllowed() {
$age = (int)$user->getAge();
// Not sure what happens if return is "null" or not castable
}
...
public function getAge() { ... }

• Passer un conteneur en paramètre de la méthode, qui recevra le retour de celle-ci (une fausse-solution, puisque le getter est en fait déporté sur une autre classe)

public function isAllowed() {
// Forces us to create an Integer class (typehinting is only allowed for classes)
$age = new Integer(0);
$user->getAge($age);
}
...
public function getAge(Integer &$ageContainer) {
$ageContainer->setValue($this->age);
// We can call it "set" if spec says "Integer assures that getValue will return what setValue was"
}



RE: Compass : East Oriented - niahoo - 24-04-2015

Dans PHP 7 on aura le typage de retour. Mais en attendant il suffit simplement de faire des tests. Parce que la, le code il est franchement pas évident à lire. Je plussoie Xenos sur l'ensemble des ses remarques.

Et ton post est sexiste (bon pas vraiment mais y avait quand même d'autres exemples dispo).


RE: Compass : East Oriented - Xenos - 24-04-2015

Faire des tests, style instanceof (ou typeof, j'ai un doute?!)? Ou des classes de test qui testent le type de retour pour voir s'il n'est pas cassé (sachant à quel point j'adore ce principe de tester quelques exemples pour inférer un comportement global)?


RE: Compass : East Oriented - niahoo - 24-04-2015

Non bah des tests quoi, du TDD. Comme ça si tu renvoies "15 years" au lieu de 15 ça se voit vite.


RE: Compass : East Oriented - Xenos - 24-04-2015

PHP permet des trucs assez exotiques, donc les tests, on ne peut pas se reposer à 100% dessus

Citation :"15" == 15 → true
"15" === 15 → false
15 == "15 years" → true
"15 years" == 15 → true
"15 years" === 15 → false
"x15 years" === 15 → false
" 15 years" === 15 → false
(int)"15 years" == 15 → true
(int)"15 years" === 15 → true
is_int("15 years") → false

Sinon, oui, dans l'idée "Mon code client se repose sur la documentation qui dit 'c'est un int', et les tests (pas coté code client) essaient de s'en assurer au mieux"... Pourquoi pas.

T'as le lien pour PHP 7 qui implémenterait le typehinting dans les retours de méthodes/fonctions?


RE: Compass : East Oriented - niahoo - 24-04-2015

à mon avis le simple test suivant permet de s'assurer que la classe renvoie bien ce qu'on s'attend à ce qu'elle renvoie :


is_integer($value)

Avec ça, si quelqu'un change ce que la classe renvoie, ton test échoue et tu peux faire ce qu'il te convient pour corriger le bug. Pas besoin d'autres tests pour s'assurer de la valeur de retour.

PHP 7 
https://wiki.php.net/rfc/scalar_type_hints_v5
https://github.com/php/php-src/blob/master/NEWS#L77


RE: Compass : East Oriented - Xenos - 25-04-2015

Pas faux.

J'en ajoute une, d'objection, puisque je suis en train de me battre avec du C++ sur Netbeans (qu'est ce que je fous sur cet IDE pour ce langage >.<):

6) Les dépendances circulaires
East me semble créer énormément de dépendances circulaires. Par exemple, "User" a besoin de "Country" en OO classique, et c'est tout, d'où un schéma de dépendances User → Country. En East, User a besoin de Country qui a besoin de User (pour lui renvoyer des infos): on a une dépendance circulaire.
Autant en PHP, on s'en cogne, mais dans d'autres langages (au hasard donc, le C/C++), il y a de quoi s'arracher les cheveux.


RE: Compass : East Oriented - srm - 12-05-2015

Demain est un grand jour, car au PHP Tour Frédéric Hardy va présenter une conférence sur East !

Et je viens de voir que j'ai raté pas mal de discussions ici, donc je relis ça et vais y répondre Smile