Browsing Category

App

Ma Première Application Javascript

Présentation

Dans le cadre de ma formation à Ironhack, je dois réaliser un projet final en javascript qui reprend tous les concepts traités lors des précédentes semaines. Mongo, Express, Vue & Node : tout y passe. À ces fins, je souhaite retranscrire jour après jour la manière dont je vais développer cette application.

mevn-javascript

Ce journal de développement a également pour but de montrer à tous mes lecteurs no-tech qu’il est possible de rapidement se mettre à niveau et de pouvoir développer ses projets. Bien évidemment, il reste pas mal de chemin à parcourir avant de pouvoir maintenir une application grand public, mais réaliser un MVP est dorénavant tout à fait jouable.

Ainsi, lors des deux prochaines semaines, je tâcherais d’éditer quotidiennement cet article afin de vous donner tous les détails de ma démarche.

Pour ce projet, j’ai souhaité réaliser une application de dating.

Problématique

Tinder a frappé un grand coup en imposant un standard sur les applications de rencontre : le swipe. Cependant, des applications ont réussi à se frayer un chemin sans utiliser cette fonctionnalité. Je pense notamment ici à Happn qui s’adosse sur la géolocalisation de ses utilisateurs.

Toutefois un outsider, Bumble, réussit à sortir son épingle du jeu. La feature #1 est la suivante : les filles amorcent les discussions sous 24h après le match sinon la mise en relation est supprimée.

Il est intéressant également de citer Abricot qui réinvente l’agence matrimoniale et qui rencontre un succès conséquent auprès des femmes.

Suite à quelques interviews, j’ai pu détecter, auprès des filles, que les applications (comme Tinder qui n’émettent aucun type de restrictions) ont de moins en moins le vent en poupe. On a tous ce pote qui est capable de liker 300 matchs / seconde :)

En effet, il existe un déséquilibre majeur entre les aspirations des femmes et des hommes sur ce type d’application. Le comportement des hommes est parfois perçu comme déplacé par les femmes.

Données

Aujourd’hui, près d’une parisienne sur deux est célibataire. – source : étude ifop – lci

Les applications de rencontres sont démocratisées chez les jeunes (28% des 18-25 ans) et chez les CSP+ (16,3%) – source : BVA

Les utilisateurs n’hésitent pas à avoir plusieurs applications – source interviews

Une personne sur deux avoue à son entourage sa présence sur une application.  – source : BVA

Il est plus facile de faire venir des hommes sur une application mobile que des femmes. – source : interviews & intuition :)

Réponse

Dans un souhait de rendre l’application plus authentique que le niveau moyen, l’idée est ici de contraindre le swipe grâce à un quizz.

Exemple : Je suis l’utilisateur A, je trouve les photos et la description de l’utilisateur B intéressantes, je like ce profil et l’application m’impose de répondre à un quizz, préalablement édité par B, avec des thèmes comme la musique, les films, les voyages ou encore les livres. Si mon taux de réussite est satisfaisant, B sera notifié que je souhaite rentrer en relation avec.

QCM

Véritable pierre angulaire de ce projet, ce quizz a donc vocation d’augmenter la friction sur la mise en relation. Des questions à choix multiples permettent ici de rendre cette fonctionnalité possible à la fois sur un plan d’expérience utilisateur que sur un plan technologique.

En connectant les API de Spotify, IMDB, Google Places et Books il est possible de traiter des cellules très classiques comme :

  • Musique : quel est ton artiste préféré ? quelle est ta musique du moment ?
  • Cinématographie : quel est le film qui t’a le plus marqué ? qui est ton acteur favori ?
  • Voyages : ta destination de vacances préférée ? ton prochain voyage ?
  • Littérature : quel est ton livre de chevet en ce moment ? l’auteur qui t’a le plus inspiré ?

Seuil

L’utilisateur a toutefois la possibilité de garder un contrôle sur cette friction en déclarant un % de réussite minimum/maximum.

Par exemple, un utilisateur qui souhaite recevoir des notifications uniquement en provenance d’autres utilisateurs qui ont réussi à remplir parfaitement le quizz. À l’inverse, un utilisateur pourrait décider d’être notifié sans une seule réponse juste à son quizz.

L’utilisateur gardant, bien entendu, la possibilité d’accepter ou non la mise en relation.

Si l’utilisateur valide, la messagerie sera activée pour cette connexion. Le concept de l’application permet également de briser la glace plus rapidement grâce au quizz préalablement rempli.

Exemple :

Toi aussi tu es fan de Tarantino ?

Technologies employées

Pour arriver au résultat escompté, voici les ensembles technologiques que je vais utiliser :

  • Database : MongoDB + Mongoose
  • Back : Nodejs + Express
  • Front : Vuejs + Vuerouter
  • Mobile : React + ReactNative (dans un second temps)

Prochaines étapes

Comme précédemment décrit, je vais faire tout mon possible pour vous retranscrire mon parcours du combattant. Mais à cette étape du projet, je suis intéressé d’avoir des beta testeurs qui ont des idées/suggestions à proposer.

Jour #1 : Conception

Une journée sans ouvrir mon éditeur de texte c’est l’objectif que je me suis fixé. J’ai déjà réalisé des mini projets qui avaient été attaqués trop tôt sous un aspect technique. Au détriment de la conception et de l’expérience utilisateur. Aujourd’hui, l’idée était de récupérer un maximum de feedbacks de la part de mes camarades de classe. Cet exercice est obligatoire et vous évite à coup sûr des erreurs bien plus difficiles à rattraper par la suite. Grâce à cette première étape, et à plusieurs interviews dispensés au préalable, j’ai pu affiner quelques détails, notamment sur le parcours utilisateur.

Quand demander telle ou telle information ?

Que faire si l’utilisateur ne souhaite pas donner ses informations ? Son quizz ?

Pour le reste de la journée, je me suis seulement attelé à dessiner mes wireframes. Mais soyons honnête, je vais m’inspirer très fortement de l’application desktop de Tinder.

tinder desktop
Pas la peine de réinventer la roue :)

La seule grande différence résidera donc au like qui enverra vers un formulaire édité par l’utilisateur « swipé ».

Schéma de données

Ce fût de loin la tâche la plus complexe de ma journée. En effet, la schématisation de vos données peut vous faire gagner beaucoup de temps, ou vous en faire perdre beaucoup par la suite.

Voici donc les 4 principaux modèles qui devraient me permettre de faire tourner mon application :

  • User : où seront recensées les id, la bio, les photos etc…
  • Quizz : ce modèle étant relié à l’utilisateur
  • Match : qui représentera la réussite d’un questionnaire, avec ses réponses et les 2 user id concernés
  • Conversation : le modèle qui acceptera tous les messages échangés

Ce dernier étant généré lorsque le modèle Match passera pending à granted (deuxième utilisateur validant la mise en relation).

N’hésitez pas à cette étape du projet de sortir votre stylo et votre feuille de papier.   

Gagner du temps

Pour faciliter la tâche lors de l’élaboration du questionnaire, je souhaite connecter plusieurs API afin de :

  • Proposer un choix exhaustif
  • Sanitizer mes données
  • Construire plus rapidement des QCM car les questions ouvertes sont, dans un premier temps, difficiles à gérer

J’ai donc pris la peine de créer une Google Spreadsheet avec tous mes logins, mot de passes, clés API et documentations associées.

Repo

L’appel du clavier. J’ai pas pu résister à écrire quelques lignes. Ou plutôt exécuter quelques lignes de commande pour générer mon application. Pour ce faire, voici les lignes de commande à taper depuis un dossier commun.

$ express server
$ cd server
$ npm install
$ npm start
$ cd ..
$ vue create client
$ cd client
$ npm install
$ npm run serve

Pour express pas besoin de views. Vous pouvez nettoyer votre dossier. Au niveau de vuejs, il suffit de rajouter vue router et la vie est belle.

express-setup vuejs-setupJe vérifie que sur les ports 3000 et 8080 mes deux environnements fonctionnent.

Même si c’est pas tout à fait ça, voici à quoi devrait ressembler approximativement votre application après ce setup.

Plus ou moins…

Jour #2 : Modèles & Signup

On commence à rentrer dans le vif du sujet. L’objectif du jour était de :

  • Créer mes modèles grâce à Mongoose
  • Générer des seeds (données fausses basées sur le schéma)
  • Monter un sign-up via Facebook

L’objectif est atteint, non sans peine, mais tout est prêt pour démarrer l’application côté base de données.

Modèles & Seeds

Je vais pas détailler ici mes 4 modèles mais plutôt un seul, le modèle User.

const mongoose = require('mongoose');
const Schema = mongoose.Schema;

const userSchema = new Schema({
  facebookId: {
    type: String,
    required: true
  },
  status: {
    type: String,
    required: true,
    default: 'pending',
    enum: ['pending', 'granted', 'killed']
  },
  gender: {
    type: String,
    required: true,
    enum: ['1', '2']
  },
  lookingFor: {
    type: String,
    enum: ['1', '2']
  },
  firstName: {
    type: String,
    required: true,
  },
  age: {
    type: Number,
    required: true,
    min: 18,
    max: 99,
  },
  bio: {
    type: String,
    maxlength: 280
  },
  work: {
    type: String,
    maxlength: 70,
  },
  mail: {
    type: String,
  },
  phone: {
    type: String,
    minlength: 10,
    maxlength: 12
  },
  photos: {
    type: String,
  },
  createdAt: {
    type: String,
    default: new Date(),
  },
  updatedAt: {
    type: String,
    default: new Date(),
  }
});

const User = mongoose.model('User', userSchema);
module.exports = User;

Ce modèle est classique mais reprend tous les champs nécessaires pour la suite (enfin, je crois).

Je pense qu’il est cependant important de garder des traces des créations, modifications (cf createdAt & updatedAt).

Le gender et le looking for me permettant de gérer par la suite les différentes orientations sexuelles.

Pour vérifier que tout fonctionne, l’idée est de créer un seed pour bien vérifier que mon application envoie les données souhaitées dans ma base de données (MongoDB). Pour ce faire, voici un script d’exemple :

const mongoose = require('mongoose');
mongoose.connect(process.env.MONGODB_URI);
const User = require('../../models/user.js');

let userDatas = [
  {
    facebookId: '123456789',
    status: 'pending',
    gender: '1',
    lookingFor: '2',
    firstName: 'Vivian',
    age: 29,
    bio: 'Lorem ipsum dolor sit amet',
    work: 'Student @Ironhack',
    mail: 'yolo@yolo.com',
    phone: '0667721671',
    photos: 'https://lh3.googleusercontent.com/-QRfzdXqbRk0/AAAAAAAAAAI/AAAAAAAARKU/0mVuCX8pVhM/s60-p-rw-no/photo.jpg',
  }
]

User.create(userDatas, (err, user) => {
  if (err) {
    throw err;
  }
  else {
    user.forEach(user => {
      console.log(user);
    });
  }
  mongoose.connection.close();
});

TA-DA ! Ça fonctionne !

Le plus dur c’est de faire le premier, après le reste ça roule. C’est une partie qui peut paraître anodine mais pourtant essentielle.

Signup

Bon là par contre, c’est un peu l’enfer. Pour avoir discuté avec plusieurs développeurs, plus ou moins chevronnés, le sign-up / login est toujours une plaie à coder. Même si il est vrai que des initiatives comme Passport ou JWT vous change la vie, ça reste une étape fastidieuse.

Pour mon application, j’ai pris le parti de ne permettre uniquement le login via Facebook. C’était un choix que nous avions fait à l’époque pour le projet MyBetFriend et nous n’avions pas eu à l’époque de retours négatifs. De plus, la quasi totalité des applications de rencontre ont déjà évangélisé cette manière de s’inscrire.

Pour récupérer :

  • Mail
  • Prénom
  • Genre
  • Photos
  • etc…

Facebook fonctionne à la perfection :)

Le conseil que j’aurais à donner pour cette partie, c’est de prendre le temps de créer (avec d’autres développeurs éventuellement) un boilerplate qui sera réutilisé à l’avenir.

Jour #3 : Préparation de l’API

Journée de transition. En ce troisième jour, je ne fus pas à 100% sur le développement de mon application. Cependant, à cette étape du projet, un travail considérable a pointé le bout de son nez : la réalisation de mon API REST.

Cette API a pour vocation de faire communiquer ma partie client (vuejs) avec mon serveur (express).

J’ai pu d’ores et déjà constaté une erreur sur mon signup. En effet, j’ai réalisé ce dernier côté serveur alors qu’il aurait été plus productif de le réaliser côté client d’entrée. Mais bon c’est en faisant qu’on apprend de ses erreurs non ?

Signup & données

Je me suis donc attaché aujourd’hui à transférer mon signup sur ma partie client et a commencé la préparation de mon API. J’ai pu également améliorer la phase d’inscription en faisant matcher les données Facebook avec mon modèle de données. Grâce à cela, je peux dorénavant faire correspondre le prénom de l’utilisateur sur Facebook avec mon modèle de données.

Je pensais (naïvement) qu’il allait être aisé de rapatrier les photos d’un profil sur mon modèle mais ce thread ouvert sur Stackoverflow m’a quelque peu refroidi.

Il faut dorénavant fournir un screencast de son application à Facebook pour avoir la possibilité de récupérer les photos de profil.

Je vais donc devoir attendre d’avoir une application un peu plus précise pour pouvoir soumettre ma review.

Timestamps

Mais j’ai découvert une astuce relativement intéressante sur Mongoose qui me va me permettre de récupérer mes timestamps lors des créations et des modifications de mes données utilisateurs.

Le tout de manière très simple en rajoutant en second argument de mon modèle :

{
  timestamps: true
}

Ce qui donne en sortie :

J’ai également mis à jour mon modèle en remplaçant les 1 et 2 par male et female.

API

Pour en revenir sur l’API, l’idée est d’écrire côté client un fichier api.js qui va interroger mon serveur. Pour protéger ces routes, je vais utiliser mon token généré au signup.

J’utiliserai donc ici le module axios pour me faciliter la vie.

import axios from 'axios'

const mtmt = axios.create({
  baseURL: process.env.API_URL || 'http://localhost:3000/',
});

Demain c’est donc un gros chantier qui m’attend, la réalisation des premières méthodes de mon API pour récupérer toutes les datas nécessaires côté client.

Jour #4 : API & Vuejs – Tome I

Si Google est ton ami, Postman est ton meilleur ami. Surtout quand tu commences à écrire ta première API REST. Effectivement, gérer une application de A à Z commence à devenir complexe. Gérer 4 environnements (front, api, serveur et db) et les faire communiquer entre eux n’est pas plus chose aisée. Surtout lorsque vous commencez à rencontrer des problèmes de type CORS.

CORS

Cross-Origin Resource Sharing… Vous ne connaissiez pas cette acronyme ? Vous en avez de la chance. Le cross origin c’est ce qui va permettre de faire discuter votre front (qui tourne chez moi sur un localhost:8080) avec votre serveur (localhost:3000). Dans un soucis de sécurité, votre navigateur n’accepte pas aisément ce va et vient incessant entre ces deux origines. Heureusement qu’il existe une extension Chrome pour gérer ce genre de soucis.

Ne pas oublier que sur des sites comme Facebook ou encore Github le comportement est parfois hasardeux si l’extension est activée.

Node –inspect

Aka la commande qui te sauve la vie ! Effectuer des console.log(‘tutu’) côté client ça va, mais côté serveur on fait comment pour se déboguer ? Heureusement que cette commande existe et qu’elle vous permet d’ouvrir une interface ad hoc pour pouvoir insérer des points d’arrêts dans votre code côté serveur.

Signup

Encore et toujours la même histoire…

Bon, ils sont bien gentils Facebook, mais réaliser un sign-up correct avec eux c’est quand même pas si évident. Je pense que la prochaine fois ça va partir sur du Firebase direct !

En clair, voici le nouveau chemin pour faire fonctionner tout ce beau monde :

  1. Front : clique sur le sign-up
  2. Facebook : retourne les informations dans mon serveur (id, firstName…)
  3. Serveur : envoie le token et les informations de Facebook via un redirect
  4. Front : utilise les req.params pour faire tourner l’application
  5. Il y’a pas de 5, ça suffit.

Vuejs, les prémices

Sur les conseils de mes professeurs émérites, il est de bon ton de développer le front et l’api en même temps, afin de cadrer au mieux avec les desiderata des futurs utilisateurs. C’est donc ainsi que j’ai commencé à faire avancer mon front.

Je saluerai donc jamais assez les personnes qui vont vivre les repos comme Buefy ou Element. Ces modules permettent de réaliser des composants à la vitesse de l’éclair et ça c’est cool.

 

Par exemple, pour proposer un range d’âge sur mon application, voici le composant récupérer sur Element :

Maintenant que mon sign up est en place, il me reste plus qu’à attaquer ma fonctionnalité quizz qui ne sera pas une mince affaire non plus.

Jour #5 : API & Vuejs – Tome II

‘Va y’en avoir combien des tomes ?!?

Il me reste 9 jours de code et j’ai l’impression que j’avance pas. Je veux pas sortir les violons, mais quand même, ce n’est pas chose aisée. Surtout quand votre IDE (Visual Code) décide de péter un plomb. 2 heures de perdues, merci.

Spotify

Le gros morceau de la journée fût de connecter l’API de Spotify à mon modèle de Quizz. Lors du sign-up je demande à l’utilisateur quel est son groupe préféré.

C’était assez chronophage car je devais récupérer le code, puis le token mais bon c’est très instructif. Autre avantage, je vais pouvoir dupliquer sur mes autres API rapidement ce week-end.

En parallèle de ça, j’apprends aussi React (qui est probablement un peu plus complexe pour un débutant). Je veux pas rentrer dans une guéguerre stérile sur les différents frameworks javascript, mais il faut reconnaître que Vuejs à quelques avantages vis à vis de React.

Syntactic sugar

Vuejs est assez facile à lire et à écrire. Par exemple, pour ma génération d’artistes, voici ce que j’ai pu faire :

<figure class="image is-4by3">
  <img v-if="artist.images[0]" v-bind:src=artist.images[0].url alt="Placeholder image">
  <img v-else src="https://placehold.it/600x600" alt="Placeholder image">
</figure>

Spotify n’a pas d’image pour tout ses artistes. Et si une image manque, c’est toute la requête qui tombe à l’eau. Grâce à Vuejs, en 2 lignes de code, vous pouvez vous prémunir de ce genre de comportement. Et ça c’est cool.

T’as la photo c’est bien, tu l’as pas, placehold.it fera le reste !

Jour #6 : API & Vuejs – Tome III

Autre avantage, je vais pouvoir dupliquer sur mes autres API rapidement ce week-end.

Rien.

N’est.

Rapide.

Je devrais le  savoir quand même ! Il est vrai que j’ai pu transposer ma recherche de musique sur les films relativement rapidement. L’API de TMDB est super bien faite et il existe de nombreux wrappers sur GitHub.

Mais en partageant mon projet à une amie, elle m’a fait une remarque pertinente.

Non mais c’est bien gentil les musiques, les films, mais le trait de caractère c’est quand ?

Spafo. Du coup, j’ai mis de côté les intégrations API pour partir sur un autocomplete très simple : qualité & défaut.

Autocomplete

Quelle joie ce Buefy. Vous pouvez facilement trouver votre bonheur dans la partie Forms Controls.

Source : https://buefy.github.io/#/documentation/autocomplete

<template>
    <section>
        <p class="content"><b>Selected:</b> {{ selected }}</p>
        <b-field label="Find a JS framework">
            <b-autocomplete
                rounded
                v-model="name"
                :data="filteredDataArray"
                placeholder="e.g. jQuery"
                icon="magnify"
                @select="option => selected = option">
                <template slot="empty">No results found</template>
            </b-autocomplete>
        </b-field>
    </section>
</template>

<script>
    export default {
        data() {
            return {
                data: [
                    'Angular',
                    'Angular 2',
                    'Aurelia',
                    'Backbone',
                    'Ember',
                    'jQuery',
                    'Meteor',
                    'Node.js',
                    'Polymer',
                    'React',
                    'RxJS',
                    'Vue.js'
                ],
                name: '',
                selected: null
            }
        },
        computed: {
            filteredDataArray() {
                return this.data.filter((option) => {
                    return option
                        .toString()
                        .toLowerCase()
                        .indexOf(this.name.toLowerCase()) >= 0
                })
            }
        }
    }
</script>

Comme vous le remarquerez, même la partie .js est gérée. Terminé bonsoir.

Demain petite pause, je vais intégrer la landing page et lâcher un peu le duo infernal Express / Mongoose.

Jour #7 : Landing Page

Petit dimanche détente, intégration de ma landing page. OKLM.

Mon premier jet est disponible ici.

Étant donné qu’il faudra fournir une landing page de notre projet, autant le faire maintenant. Je pense que je serai tellement emmerdé par ma mise en production plus tard…

Mais ce n’est pas une excuse pour faire une landing page moisie. J’ai souhaité incorporer de la parallaxe et quelques animations CSS. Pour ce faire j’ai utilisé deux ressources très intéressantes : paroller & animista.

Paroller

Source : https://github.com/tgomilar/paroller.js/

Paroller est un plugin basé sur jQuery qui permet des animations parallaxes très facilement. Alors oui je sais, utiliser jQuery c’est le mal gnia gnia… Mais bon, ça marche, c’est facile, pas la peine de perdre des heures à reproduire la même chose avec du Tween non ?

Ce que j’ai le plus apprécié dans paroller c’est sa facilité de mise en place. Il suffit de déclarer une classe sur la partie qu’on souhaite animer et la suite se gère très bien :

$(".p1, [data-paroller-factor]").paroller({
  factor: 1,              // multiplier for scrolling speed and offset
  type: 'foreground',     // background, foreground
  direction: 'horizontal' // vertical, horizontal
});

Il suffit de gérer ces 3 paramètres et le tour est joué.

Animista

Source : http://animista.net/

Animista c’est le Google des animations css. Il suffit de piocher son animation, copier coller sa classe, ses keyframes et ça marche.

Jour #8 : De la data

Journée relativement productive. Mise à jour du Trello, finalisation du quizz. J’attaque maintenant le gros morceau : l’interface de mise en relation (swipe + quizz + chat). Mais avant cela, deux travaux relativement importants : enregistrer l’utilisateur localement (local storage) et création de faux profils.

Ce n’est pas pour faire semblant d’avoir une croissance exponentielle, non c’est plutôt pour tester tous les cas de figures. Les combinaisons possibles de recherches sont très élevées (âge, âge recherché, sexe et orientation sexuelle).

Enregistrer l’utilisateur localement

J’avais mis ça de côté en pensant que c’était pas trop compliqué à faire par la suite. C’est le cas, mais autant le faire de suite la prochaine fois :)

data: function() {
    return {
      error: null,
      files: [],
      photos: '',
      id: this.$route.query.id,
      firstName: this.$route.query.firstName
    }
  }

Au sign-up, je récupère l’id depuis l’url de callback de Facebook.

Une fois présenté, je suis en mesure de l’envoyer, avec axios, dans mon local storage (developer tools > application > local storage).

NB : j’envoie aussi mon token mais pas au même endroit :)

.then( res => {
        const { data } = res;
        localStorage.setItem('id', obj._id);
        axios.defaults.headers.common['Authorization'] = 'Bearer ' + data.token;
        return data;
      })

C’est pas les lignes de code de l’année mais ça fait le taf.

Par la suite, je récupère facilement l’id comme suit :

        .sendTreshold({
          userId: localStorage.getItem('id'),                
          treshold: this.treshold
        })

Faker.js

La trouvaille. Je pensais devoir scrapper des sites de rencontre pour pouvoir avoir une première base de test. Mais bon, comme vous devez le savoir, le scrapping, c’est pas bien.

Heureusement je suis tombé sur Faker qui est une librairie permettant de générer des quantités phénoménales de données. L’un des énormes avantages, c’est que Faker est capable de rester fidèle à la localité. Ce qui permet, dans mon cas, de mettre uniquement des personnes françaises.

const mongoose = require('mongoose');
mongoose.connect(process.env.MONGODB_URI || "mongodb://localhost/mtmt");
const User = require('../../models/user.js');

var faker = require('faker');
faker.locale = "fr";

var file = [];
for (let i = 0; i < 2000; i++) {
  
  let fakeDatas = {
    facebookId: faker.random.number(),
    status: 'granted',
    gender: faker.random.arrayElement(['male', 'female']),
    lookingForGender: faker.random.arrayElement(['male', 'female']),
    lookingForRange: [{'min' : faker.random.number({min:18, max:24}), 'max' : faker.random.number({min:32, max:49})}],
    firstName: faker.name.firstName(),
    age: faker.random.number({min:18, max:49}),
    bio: 'Je suis un faux compte et je le vis bien.',
    work: faker.company.companyName(),
    mail: faker.internet.exampleEmail(),
    phone: faker.phone.phoneNumber(),
    photos: faker.image.avatar(),
  }
  file.push(fakeDatas)
}

User.create(file, (err, user) => {
  if (err) {
    throw err;
  } else {
    user.forEach(user => {
      console.log(user);
    });
  }
  mongoose.connection.close();
});

Extrait :

{ facebookId: '37981',
  status: 'granted',
  gender: 'male',
  lookingForGender: 'female',
  lookingForRange: [ { min: 22, max: 46, _id: 5a9e51b9c932da671f9b1c2b } ],
  firstName: 'Lena',
  age: 48,
  bio: 'Je suis un faux compte et je le vis bien.',
  mail: 'Pauline90@example.net',
  phone: '0689125768',
  photos: 
   [ 'https://s3.amazonaws.com/uifaces/faces/twitter/nfedoroff/128.jpg' ],
  swiped: [],
  _id: 5a9e51b9c932da671f9b1c2c,
  createdAt: 2018-03-06T08:30:49.843Z,
  updatedAt: 2018-03-06T08:30:49.843Z,
  __v: 0 }
{ facebookId: '74494',
  status: 'granted',
  gender: 'male',
  lookingForGender: 'female',
  lookingForRange: [ { min: 19, max: 45, _id: 5a9e51b9c932da671f9b1c2d } ],
  firstName: 'Célia',
  age: 41,
  bio: 'Je suis un faux compte et je le vis bien.',
  mail: 'Lo_Leroux@example.com',
  phone: '+33 614805908',
  photos: 
   [ 'https://s3.amazonaws.com/uifaces/faces/twitter/kianoshp/128.jpg' ],
  swiped: [],
  _id: 5a9e51b9c932da671f9b1c2e,
  createdAt: 2018-03-06T08:30:49.843Z,
  updatedAt: 2018-03-06T08:30:49.843Z,
  __v: 0 }

La vie est belle.

Jour #9 : Vuejs et ses composants

J’ai pu goûter aujourd’hui à la puissance de  Vuejs. Autre force de ce framework c’est la structuration de ses composants et de ses vues.

Pour mon interface de swiper j’ai donc un composant Card et un autre Quizz. Ces deux composants se retrouvant dans une vue Swiper.

  1. Swiper.vue – view
  2. Card.vue – component
  3. Quizz.vue – component

De base, le quizz est désactivé. Je l’active sur le click Like sur la Card.vue. Mais je le referme depuis le composant Quizz.vue grâce à un event : $this.emit(‘hide’)

Ce dernier est récupéré dans Card.vue avec @hide=hideQuizz

Plutôt facile non ?

Dernière petite astuce, utiliser beforeMount() pour charger l’API avant le composant dans le but d’afficher de la data dès que le composant prend vie.

Jour #10 : Like & Dislike + Heroku

Je dois présenter mon projet vendredi. Ça serait pas mal de faire les fonctionnalités annoncées non ? Avec un petit déploiement également ?

Aujourd’hui je me suis donc attaché à coder mes features clés qui Like & Dislike l’utilisateur avec une première mise en production pour pas avoir trop mal vendredi matin.

De toutes façons on fait jamais une MEP un vendredi… Source

Like & Dislike : MongoDB & Vuejs

Pour que l’application cadre avec le souhait de l’utilisateur, il est impérieux de proposer des profils qui cadrent avec le sexe, l’orientation sexuelle et l’âge.

Pour ce faire…

Ma route

router.get('/api/getmatches/:id', function (req, res, next) {
  User.findById(req.params.id, function (err, user) {
    if (err) {
      next (err);
    } else {
      User
      .find({
        gender: user.lookingForGender,
        age: { $gte : user.lookingForRange.min, $lte: user.lookingForRange.max } 
      })
      .limit(100)
      .exec((err, users) => {
        if (err) {
          next(err);
        } else {
          res.json(users)
        }
      })
    }
  })
})

Qui sera améliorée demain bien entendu…

Comme vous le voyez, rien de très compliqué. En fonction de l’id de l’utilisateur, je récupère les informations nécessaires pour lui proposer les matches qui correspondent à ses envies.

Par la suite, je requête la base en entier sur ses critères. Je limite à 100 dans un premier temps, pas besoin de plus pour tester.

Mes méthodes

methods: {
    getMatches() {
      api
        .getMatches(localStorage.getItem("id"))
        .then((users) => {
          this.users = users
        })
        .catch(err => {
          this.error = err;
        })
    },
    increment(){
      this.counter++;
    }
  },
  beforeMount() {
    this.getMatches()
  },

Sur Vuejs il faut conceptualiser plusieurs choses.

L’appel de l’API se fait bien sur la base de l’id de l’utilisateur. C’est donc tout naturel de le récupérer depuis le local storage. 

Ce que j’utilise en revanche c’est une incrémentation pour faire passer les profils les uns après les autres. Il serait peut être intéressant que je filtre l’objet en sortie sur la date d’inscription, pour faire passer en avant les anciens profils. À voir.

Ne pas oublier le beforeMount() et on est bons.

Heroku

Mouairf… Pas très glorieux tout ça. Le déploiement est à mon sens une tâche réellement ingrate. Très difficile à déboguer, vous pouvez passer un temps considérable pour un résultat faible. Bon, il est vrai que vous pourrez toujours crâner auprès de vos petits copains en fin de journée.

Trève de plaisanteries, Heroku est quand même bien pratique et très bien documenté. En plus c’est gratuit.

Jour #11 & #12 : Fin.

Pour les derniers jours impossible de prendre le temps d’écrire. Sur la journée #11 j’ai réalisé pas moins de 20 commits sur mon application. Record battu :)

Quizz

Sur cette journée j’ai tout simplement réussi à mettre en place ma fonctionnalité principale : le quizz.

La plus grande complexité fût de réaliser des faux quizz et des les lier aux faux utilisateurs.

const mongoose = require("mongoose");
mongoose.connect(process.env.MONGODB_URI || "mongodb://localhost/mtmt");
const Quizz = require("../../models/quizz.js");
const User = require("../../models/user.js");

var faker = require("faker");
var randomArtists = require("./random/randomArtists");
var randomMovies = require("./random/randomMovies");
var quality = require("./random/quality");
var defect = require("./random/defect");

var users = [];
User.find({})
    .select({
        _id: 1
    })
    .limit(100)
    .exec((err, users) => {
        if (err) {
            next(err);
        } else {
            var file = [];
            for (let i = 0; i < 20000; i++) {
                let fakeDatas = {
                    userId: faker.random.arrayElement(users),
                    treshold: faker.random.number({ min: 0, max: 100 }),
                    music: {
                        answer: faker.random.arrayElement(randomArtists),
                        badResponses: [
                            faker.random.arrayElement(randomArtists),
                            faker.random.arrayElement(randomArtists),
                            faker.random.arrayElement(randomArtists)
                        ]
                    },
                    movie: {
                        answer: faker.random.arrayElement(randomMovies),
                        badResponses: [
                            faker.random.arrayElement(randomMovies),
                            faker.random.arrayElement(randomMovies),
                            faker.random.arrayElement(randomMovies)
                        ]
                    },
                    traits: {
                        "quality.answer": faker.random.arrayElement(quality),
                        "quality.badResponses": [
                            faker.random.arrayElement(quality),
                            faker.random.arrayElement(quality),
                            faker.random.arrayElement(quality)
                        ],
                        "defect.answer": faker.random.arrayElement(defect),
                        "defect.badResponses": [
                            faker.random.arrayElement(defect),
                            faker.random.arrayElement(defect),
                            faker.random.arrayElement(defect)
                        ]
                    }
                };
                file.push(fakeDatas);
            }

            Quizz.create(file, (err, quizz) => {
                if (err) {
                    throw err;
                } else {
                    quizz.forEach(quizz => {
                        console.log(quizz);
                    });
                }
                mongoose.connection.close();
            });
        }
    });

Pour ce faire j’utilise toujours ce bon vieux Faker.js qui fait gagner un temps considérable. Une fois le fichier créé je le pousse en base via Mongoose.

Refacto

Sur la doc de React j’ai trouvé une partie très intéressante : Thinking In React. Je n’ai pas (encore) trouvé son pendant côté Vuejs.

Cette partie  vous explique comment découper une petite application web en composants. C’est très intéressant, car si vous commencez à créer une application avec une architecture bancale, la moindre fonctionnalité va devenir très compliquée à produire.

C’est en ce sens que j’ai souhaité (la veille de mon rendu) « refactoriser » mon interface de swipe.

Ce n’est pas un choix que je regrette car j’ai pu avancer beaucoup plus vite par la suite. Je pense que pour la prochaine application, je vais utiliser beaucoup plus de papier et de feuilles blanches pour conceptualiser l’application.

Toasts

Petite fonctionnalité intéressante, qui plus est pour l’utilisateur final, le toast. C’est d’une facilité enfantine à mettre en place et le résultat est plutôt sympa pour l’utilisateur.

          .then(data => {
            this.$toast.open({
              message: "Bien reçu",
              type: "is-success"
            });
            this.$router.push("/quizz-info");
          })

Vous pouvez rajouter rapidement dans votre retour de données API ce petit bout de code qui avertira l’utilisateur que tout est OK. Le tout avant de le rediriger vers la prochaine page.

It’s a match!

Pour les besoins de la démonstration live, j’ai du mettre insérer un pattern fixe sur les bonnes réponses. J’aurais bien entendu pas fait ça comme ça pour une vraie mise en production. Mais bon j’ai codé ça en quatrième vitesse et ça faisait le taf, donc bon…

router.post("/api/postquizz/", function(req, res, next) {
    Quizz.findById(req.body._id, function(err, quizz) {
        if (err) {
            next(err);
        } else {
            var score = 0;
            if (req.body.musicAnswer === "A") {
                score = 25;
            }
            if (req.body.movieAnswer === "B") {
                score += 25;
            }
            if (req.body.qualityAnswer === "C") {
                score += 25;
            }
            if (req.body.defectAnswer === "A") {
                score += 25;
            }
            if (score > quizz.treshold) {
                Match.create({
                    _quizzId: req.body._id,
                    _userRequester: req.body._userRequester,
                    _userCandidate: req.body._userCandidate,
                    average: score / 100
                });
                res.json({
                    message: "BRAVO"
                });
            } else {
                res.json({
                    message: "NOPE"
                });
            }
        }
    });
});

npm run build

Autre élément important appris lors de ces folles journées du code, l’intérêt de faire passer un build de production assez rapidement. En effet, Vue (et les autres) vont compiler votre code et le distribuer dans un dossier /dist. Le seul petit soucis, c’est que si vous avez fait le barbare comme moi en bougeant des classes css natives vous allez retrouver votre appli tout en désordre. Donc ce qui peut être pas mal c’est de faire un build en fin de journée pour bien vérifier que tout est à sa place.

Ou sinon vous codez correctement et vous faîtes des classes partout.

Conclusion

Voila. http://mtmt.viviansarazin.com/

NB : L’application n’est pas optimale en version mobile

Deux semaines de code, une application. Je pense que la prochaine fois je pourrais faire la même application en une semaine. Mais bon il faut passer par là !

Rétrospectivement, je dirais que j’aurais pu passer un peu plus de temps sur la phase de conception afin de mieux préparer mon API, mes composants toussa toussa.

J’ai aussi perdu pas mal de temps sur le setup, plus précisément sur le signup via Facebook. La prochaine fois je pense que je partirais directement sur du Firebase. Autre possibilité, réaliser un boilerplate MEVN pour gagner du temps.

Remerciements

C’est le moment de sortir les mouchoirs. Faut bien que ça s’arrête quand même !

Pour les profs : Merci Eduardo, Guillaume, Maxence, Mickaël A, Mickaël B, Nizar & Yacine.

Et les autres : Merci Antoine, Charlotte, Karim & Maya.

 

Bien à vous :)

Pour vous inscrire à la newsletter c’est par ici :

sdk

Comment générer des hacks avec des SDK ?

La joie des stores ! J’en avais entendu parler, mais s’y confronter c’est tellement plus marrant. J’avais bien travaillé sur quelques lancements, sur de l’ASO par le passé, mais rien de comparable à ce que je vais vous présenter. De la conception en passant par ma première panne serveur, je vais tenter de vous décrire notre parcours avec MyBetFriend et vous dire comment nous nous en sommes sorti avec notamment 3 SDK fabuleux.

Concevoir une application ou l’art de perdre 5 ans d’espérance de vie en autant de semaines

Beer & Pitch

Il fallait bien y aller dans le mobile un jour. Oui, il le fallait. J’avais bien eu quelque idées mais rien de quoi constituer une équipe sur un objectif commun. Comme toute idée valable du IIIème millénaire, celle-ci naquit autour d’une pinte de bière avec un ami. Nous regardâmes un match de foot dans un bar miteux de Paris, et soudain éclair !

Parier ma bière auprès de mon ami selon l’issue du match. Tout deux fascinés par les chiffres, nous nous sommes projetés dans l’agrégation des données statistiques TV en live dans cette hypothétique application mobile.

Ça doit déjà exister… Tu penses que ça plaira ? Mouairf… C’est sympa mais bon…

Il fallut se rendre à l’évidence, mon elevator pitch était nul et donnait autant envie que la vision de Margaret Tatcher nue dans la neige (désolé…).

Face à ce premier échec, je décidais d’appeler l’éditeur de statistiques en question et de lui soumettre mon pitch. Grâce à quelques bottes secrètes je réussis à contacter mon interlocuteur 48h après mon premier coup de fil.

Après avoir pitché mon embryon de projet, je n’entendis qu’un silence pesant. Mais cette fois-ci la réponse fût positive. En fait, ce silence marquât mon premier succès, celui d’avoir attirer l’attention et proposé un service novateur auprès d’un professionnel du secteur.

Il faut être bien évidemment lucide, avec mon fournisseur nous allions commencer une relation commerciale aussi. Mais au vu et au su de son soutien indéfectible, je pense que notre alliance allât plus loin qu’une simple relation tarifée.

Les faisabilités techniques et temporelles scellèrent ma joie et firent naître mon optimisme (naïf) d’entrepreneur digital.

Un pour tous et tous pour un #YOLO

Requinqué par ce premier « succès », je fus à même de monter une équipe de 6 personnes. En l’espace de 2 mois nous étions fixé sur un nom, sur un concept, et surtout sur une finalité à donner à ce projet.

Fondamentalement, nous en avons tous marre de ce bullshit continuel «plus qu’une société, une équipe gnia gnia… » mais typiquement comment les start-up peuvent réaliser de superbes projets sans une équipe de rockstar ? Un grand groupe, avec de l’ancienneté, un réseau, une marque connue, peut se traîner des boulets dans son effectif. Une start-up non. En tout cas si elle le fait, elle finira très rapidement dans le cimetière des start-up.

Il existe plus de start-up mortes que de start-up en activité. Click To Tweet

#instantprofond

Pour en revenir à l’équipe, je dirais qu’il faut retrouver en elle tous les caractéristiques qui permettront de réaliser des 1+1=3.

Avec de la contradiction on améliore ses idées, son travail. Je pense que cette notion est tout de même fondamentale si tant est que vous recherchiez un produit qui s’adresse à autre chose qu’une étroite niche.

Et la conception fût…

J’ai pu remarquer que lorsque vous créiez une application ou quand bien même un service innovant, la majorité des personnes ont tendance à entendre ce qu’elles veulent et à devancer votre effort sacré d’imagination. Infâmes cloportes ! Même si vous pouvez avoir de superbes idées qui viennent à la volée, il va vous être impossible d’avancer sur votre projet. Vous allez déployer toutes les features suggérées par tout votre entourage et votre application ne ressemblera plus à rien.

A vouloir plaire à tout le monde, vous ne séduirez personne et même vous vous aurez un certain dégoût pour vous-même par la suite.

C’est à cette étape bien précise qu’il est de bon aloi d’utiliser Canva (ou Balsamiq) & Invision.

Grâce à ce couple de SAAS gratuit, il vous sera possible de réaliser vous même votre prototype d’application et d’itérer dessus sans même à avoir expliquer vos tenants et aboutissants.

L’UX c’est comme une blague, si tu dois l’expliquer c’est que c’est pas bon

A ce petit jeu là je peux vous garantir qu’avec mon équipe on a pas été tout le temps drôle. Loin de là. Mais mauvaises blagues après mauvaise blagues, nous avons pris le parti de simplifier notre service au maximum et surtout de s’en remettre à une chose pour trancher nos décisions : la data.

Toute le monde n’a pas le même humour. Pourtant nous partageons tous, quelques trucs en commun. Par exemple : les cons, l’air que nous respirons, les gamins qui chialent dans le train (j’en ai un à côté de moi que j’ai envie de massacrer là…), les lois de la physique et les mathématiques. Notre avions donc décidé de choisir ce dernier point pour avoir un juge de paix. C’est assez paradoxal car je connais peu de personnes qui exultent à la vue d’une feuille Excel, mais quand bien même, être data-oriented ne vous fera aucun mal si vous lancez une application.

Exemple de blague tentée : le login uniquement par Facebook. Même si ça n’a pas fait marrer tout le monde au départ, il aura gêné, in fine, 13 % de l’ensemble de nos utilisateurs. Et cette métric nous a été remontée par le premier SDK que je vais vous présenter, MixPanel.

Les SDK c’est trop bien !

MixPanel

Ai-je encore besoin de présenter MixPanel ? Oui ? Bon ok…

MixPanel est à l’application mobile ce que Michael Ange est à la renaissance italienne. (Normalement avec une présentation comme ça et un backlink aussi puissant je devrais gagner un peu de datas gratis…).

Mais arrêtons là les conneries, MixPanel est avant tout un SDK d’Analytics gratuit jusqu’à un certain niveau de consommation. De plus votre développeur n’aura aucun mal à intégrer ce SDK sur iOS & Android.

Fonctionnalités

Les fonctionnalités de MixPanel sont multiples et variées. Vous allez être tout d’abord en mesure de garder la trace de tout vos utilisateurs, définir des profils, intégrer leurs tokens pour déboguer et retrouver ainsi rapidement toutes les informations que vous souhaitez remonter.

De plus vous allez être en mesure d’intégrer des funnels de conversions qui vous montreront les différents points de frictions de votre application. A vous de travailler conjointement avec vos designers et développeurs pour éviter toutes chutes. La bonne interprétation des metrics est souvent à l’origine des hacks.

Autre fonctionnalité, les cohortes de rétentions. C’est peut être là que ça commence à vraiment devenir marrant. En effet, réaliser une application c’est cool, la développer c’est marrant mais générer de la rétention c’est générer de l’amour pour elle. On a plaisir à y aller et surtout à y revenir.

C’est là qu’on (en général) monétise et qu’on génère de la marge nette de manière durable. Difficilement ailleurs.

MixPanel présente aussi d’autres fonctionnalités comme l’A/B testing et les notifcations. Mais ça ça vient plus loin…

Alternative à MixPanel, Amplitude SDK suggéré par Alexandre Jubien de Thinkmobile

OneSignal

Le problème avec les notifications c’est qu’elles ont souvent une fâcheuse tendance à vouloir partir toutes en même temps. Et si votre développeur ne prévoit pas une méthode pour les espacer afin d’éviter un pic de charge trop violent, vous allez avoir un nombre incalculable de notifications non délivrées. Qui plus est difficile de dire à la volée combien sont envoyées, cliquées etc.

C’est à ce niveau précis que OneSignal intervient. Cette fois-ci pas besoin de cirage de chaussures, One Signal est entièrement gratuit.

Le SDK est semble-t’il un petit peu plus complexe à intégrer mais il en vaut la peine.

OneSignal vous permet d’envoyer quasiment toutes vos notifications et de surtout mesurer leurs impacts respectifs. OneSignal intègre parfaitement bien cette notion de reporting.

Cependant les fonctionnalités qui m’auront le plus servi n’auront pas étaient celle-ci.

Segments

OneSignal vous offre la possibilité de générer vos segments d’utilisateurs en fonction de :

  • Nombre de sessions
  • Durée des sessions
  • Première sessions
  • Latitude & Longitude
  • etc.

Grâce à ça vous allez pouvoir envoyer des notifications propres à chaque segments. Manuellement ou automatiquement.

Template & A/B Testing

Là ça devient très puissant. OneSignal va vous permettre d’envoyer automatiquement une notification bien précise lorsqu’un utilisateur rentre dans un segment défini.

Par exemple : nous avons défini dans MyBetFriend un segment « Hardcore users » pour les users dépassant plus de XX sessions. C’est donc à ce moment là que nous lui demandions de nous noter sur le store.

Une fois cette technique mise en place nos reviews 5 étoiles furent régulières.

Et pour bien optimiser ce processus, OneSignal vous propose de réaliser des A/B Tests pour définir le message le plus pertinent.

Que du bonheur !

Branch.io

Dernier SDK pour la route : branch.io

Bon là on frise l’indécence, l’obscène même. Toujours gratuit, ce SDK va vous permettre de générer notamment des deeplinks.

Ces liens (magiques) vont intelligemment comprendre sur quel appareil le lien est ouvert et appliquer un scénario différent.

Exemple : Si vous êtes sur un BlackBerry vous pouvez paramétrer l’ouverture du store BlackBerry bien la redirection vers votre landing page, ou bien votre liste Mailchimp.

Le SDK n’est pas évident à mettre en place, mais les deeplinks sont très puissants pour faciliter le partage. Un bémol toutefois, si vous utilisez un raccourcisseur d’url comme nous, il se peut qu’il soit mal interprété. C’est en ce sens que je vous invite à implémenter un SSL sur votre site et utiliser donc un shorter idoine.

Branch.io propose également un onboarding personnalisé. Même si cette feature nous a un temps intéressé nous l’avons (malheureusement) délaissé au profit d’autres fonctionnalités.

Néanmoins il va sans dire que pour notre V2 nous allons utiliser à fond cette feature.

Toutefois, la feature qui aura été des plus puissantes dans notre cas d’utilisation c’est la feature app banner. Même chose, selon votre device, cette banner s’ajoutera en haut de votre site réagira de différents manières :

  • Ordinateur : La possibilité d’inscrire son numéro de téléphone pour recevoir un deeplink d’installation
  • N’importe quel mobile : L’installation en renvoyant sur le ou les bons stores
  • Un mobile où l’application est déjà installée : L’ouverture de l’application
  • Et un autre mobile où l’application est déjà installée mais non à jour : La mise à jour de l’application

C’est grâce à cette banner que nous avons pu réaliser l’un de nos « hacks » les plus efficaces.

La publicité pour installation d’application étant hors de prix (1€ en moyenne) le fait d’envoyer du trafic uniquement sur notre site (CPC faible sur le foot) eut pour effet d’optimiser notre investissement.

Soit l’internaute téléchargeait l’application, soit il laissait son mail ou soit et bien il générait du trafic sur notre site. Pour ainsi dire nous évitions toutes pertes d’investissements. Si vous êtes en plus l’heureux détenteur d’un blog et/ou d’un site drainant pas mal de visites quotidiennes vous allez pouvoir assister à un bond spectaculaire (je l’espère) de vos installations.

SDK Bonus, Launchkit.io

Dernier SDK et pas des moindres, Launchkit. Récemment acheté par Google, ce SDK nous a permis de gagner énormément de temps sur :

  • Génération des images iOS (apparemment plus besoin maintenant…)
  • Onboarding
  • Review monitor

Ils ont récemment déployé sur git l’ensemble de leurs codes. A voir ce qu’ils vont réaliser par la suite avec Google.

En espérant que cet article t’a plu, on peut se retrouver sur les Internets ici. On discutera de pannes serveurs et d’AdminSys, tu verras c’est rigolo :

My Bet Friend l’application pour parier et challenger ses amis sur le foot

Comme certains d’entre vous le savent, je démarre un nouveau projet d’application mobile :  My Bet Friend. C’est une application, iOS et Android, qui permet de poser ses pronostics sur un match de foot et de défier ses amis.

Comment ça marche ?

Après avoir téléchargé et installé l’application sur votre mobile, il vous suffit de rentrer sur un match de foot, d’inscrire vos pronostics et de challenger vos amis. Ces derniers reçoivent une notification pour répondre à votre défi. Durant le match, vous allez pouvoir visualiser en live l’évolution du score avec chacun de vos amis. Grâce à notre partenaire Opta nous offrons la possibilité aux challengers de visualiser les données de leur match en temps réel sur leurs smartphones. C’est ainsi que nous offrons une expérience unique pour l’ensemble des matchs de l’Euro 2016.

Pourquoi My Bet Friend ?

Je suis passionné de Foot et j’ai toujours été frustré par le fait de ne pas avoir un outil fiable pour mesurer que de ma bandes d’amis était le meilleur en pronostics. Alors oui on a bien un tableau Veleda au boulot, mais bon c’est quand même assez old school. Le seul truc qui a la limite permettait d’avoir quelque chose de propre, c’est une feuille Excel. Mais bon l’angoisse pour tout paramétrer et tout actualiser… L’avantage c’est qu’on peut croire que vous bossez quand vous êtes dessus ;)

De plus, la France organise cette année l’Euro 2016 donc il fallait faire un choix. Y aller ou regarder le train passer ? L’avenir nous dira si il aurait plus juste de rester à quai :)

Les challenges

My Bet Friend va plus loin que la fameuse feuille Excel ou le tableau Veleda. Avec My Bet Friend vous pouvez parier sur le score mais sur pas mal d’autres items. Exemple : vous pouvez parier sur les buteurs, la possession de la balle, le premier but plus des questions bonus surprises.

Avec notre flux Opta alimenté en temps réel, nous pouvons donc proposer une expérience unique aux challengers. Les amateurs de foot le savent bien, un match peut basculer en quelques minutes. La victoire ou la défaite se joue parfois à peu de choses ! De plus on permet aux amateurs assidus de football de pouvoir suivre leurs items en live.

Le classement

Tout au long du match, on calcule (avec notre système de cotations) les points gagnés sur chaque item. Ces points sont reportés à l’issue du match sur le classement général. Ainsi, à la fin du match, il est possible de comparer les scores de chacun. On va pouvoir savoir une bonne fois pour toutes qui est le meilleur ! Finie la mauvaise foi ou les quiproquos, les chiffres annoncés sont les bons et le flux qui les alimente et le même qui est utilisé par les plus grands médias sportifs.

Actualité

Pour l’heure nous sommes en beta-tests et nous cherchons de nouveaux testeurs pour faire évoluer l’application. Si ça vous intéresse vous êtes libres de vous inscrire sur http://www.mybetfriend.fr

Vous comprendrez aisément que je ne publierais un peu moins souvent d’articles, mais les prochains seront orientés application mobile très certainement.

Vous pouvez toujours vous inscrire sur mon Slack si vous avez des demandes, je réponds dans la journée.