Si le mot "master", ou "maître" en français, vous fait automatiquement penser à l'esclavage et que l'émotion que cela suscite en vous et si forte que cela vous est insupportable, je pense que vous avez de sérieux problèmes mentaux.
Mais résumons, des gens qui n'ont jamais subit l'esclavage, imposent à des gens qui n'ont jamais détenus d'esclaves, dans un contexte ou l'esclavagisme a disparu en occident depuis plus d'un siecle voire plus de deux, en se servant d'un fait divers ou un drogué, criminel multi-récidiviste, est mort d'overdose pendant une arrestation, de transformer un standard anodin de l'informatique mondiale en centre de dépenses absurdes et inutiles pour satisfaire leur égo surdimensionné : le monde entier doit changer pour leur convenir, mais eux ne doivent pas s'adapter, ce ne serait pas "inclusif".
J'avais lu que certains renommaient leur branche "master/main" en "so" ou "slave-owner" en guise de protestation face à l'absurde. Et je comprends le geste... #WokeFatigue
Les exigences permanentes de ces divas sont insupportables. Leur valeur ajoutée pour la société est négative. Ils font perdre leur temps et épuisent ceux qui ont mieux à faire que de s'intéresser à leurs petites émotions, à leurs ressenties...
On mérite ce qu'on tolère 😡
Idée intéressante. J'ai potentiellement une variante qu'il faut que je teste et qui n'utilise pas de classe mère mais à la place, utilise une classe interne qu'on déclare dans le prototype de l'objet.
Merci à Kalvn pour le lien.
Ahhhhh enfin !
Après dès années à pester sur le fait que Spring transforme Java en une versions verbeuses de JavaScript, VMware et la communauté ont amorcé un changement majeur. L'annotation @Autowired est officiellement dépréciée !
Il faut donc le remplacer par notre chéri à tous : l'injection par constructeur !
Ce qui est juste le fonctionnement normal du langage depuis 1995... C'est fou hein ! Comme si exécuter tout un tas de méthodes avant d'exécuter un simple new était plus lent que de directement exécuter ce simple new...
Comme dirait @Timo "LA SUPRISE EST TOTALE !"
Attention @Kalvn je pense que l'auteur du billet est passé à côté de beaucoup de choses (en tout cas il n'y fait pas mention).
Fragmenter son code permet de :
1. Tester les parties de code indépendamment les unes des autres.
D'où le fait que l'exemple vienne du Google Testing Blog.
Par exemple comment faire pour tester tous les use-case du if !pizza.Baked sans avoir à écrire plusieurs tests avec plein d'autres paramètres à initialiser alors que ce bloc de code n'a besoin que de oven et pizza ? Ça devient au mieux illisible sinon impossible.
2. Paralléliser le travail.
Je peux écrire la première fonction, tu écris la deuxième. Mais si tout est dans la même fonction, impossible de se répartir le travail. Le type qui a écrit le billet ne fait-il que des projets persos ou ça lui arrive de bosser en équipe ?
3. Mutualiser le code.
Simple, une fonction par préoccupation permet de réutiliser cette fonction ailleurs. Du coup l'auteur qui préfère le gros bloc rouge avec tout dedans, il mutualise à base de copier-coller ?
À titre d'exemple, en revoyant la duplication de code d'un projet classique qui peinait chez mon dernier client, nous avons économisé ~500 K€ / an car mettre à jour un code copier-coller 15 fois, ça implique 15 mises à jour à retrouver, étudier, comprendre, patcher et tester.
4. Ne pas avoir à maintenir des commentaires.
Le nom de la fonction/méthode est la documentation de ce que fait le code, pas besoin de commentaires. D'ailleurs ce nom est toujours à jour sinon le code ne compile plus, les tests échouent ou l'algorithme ne veut plus rien dire, choses qui se remarquent.
A contrario, un commentaire erroné (en gris sur fond noir hein) ne cassera rien puisqu'une erreur n'aura pas d'incidence. Donc il aura de plus en plus de chances d'être faux avec le temps et induira nos confrères en erreur par la suite.
C'est l'un des plus gros pilliers de Clean Code de Bob Martin. Comment le mec est passé à côté, c'est fou non 🤨 ?
5. D'organiser sa pensée.
Je code souvent en TDD double loops, voire multi-loops c'est-à-dire que j'écris mon process à l'aide d'interfaces (ou méthodes) à remplir ce qui me donne le plan de quoi faire.
Mieux que cela, le plan étant rédigé au début, il est hyper facile de s'arrêter à un endroit, de le commiter/pusher, puis de reprendre plus tard, ceci sans jamais casser de features ou le code des collègues. Bonne chance avec une grosse fonction bien procédurale.
Conclusion
Ça ressemble à l'avis d'un amateur ou de quelqu'un qui ne veut pas s'embêter parce que le stress chez les autres, who cares ? Potentiellement quelqu'un qui n'a jamais eu à maintenir de code-base ayant 10 ou 20 ans de vie et qui n'a fait que des projets greenfield, ce qui renvoie à de l'amateurisme.
Désolée d'être cinglante mais
Depuis plusieurs années, différents frameworks ont émergé afin d'apporter la null-safety sur Java (Kotlin, la JSR 305, Findbugs, Spotbugs, etc). Ici, JSpecify est la fusion de ces gros frameworks en un seul standard unique.
Super ! Merci @Eric pour le lien
Page de la documentation officielle du framework CSS Bulma expliquant comment personnaliser le thème du framework en passant par les CSS var plutôt que les variables SASS.
Des transitions de pages web, en pure css, pour des MPA.
Des techniques d'optimisation de la memoire en Java. Pour @Animal
What the fuck ?
[...] Scripting allows people to express creativity and ingenuity in a way that GUIs don’t [...]
@Timo ton détecteur à pseudo-science ne fonctionne-t-il pas pour les discours pseudo-intellectuels ?
Il n'y a rien de plus antisociale que du code ! C'est tellement merdique que même des années après à pratiquer tout le temps, soirs et week-ends par passion, j'écris toujours des conneries.
L'idée du mec est de dire qu'apprendre et maîtriser du code serait plus expressif et donc plus "social" qu'une IHM car "moins contraignant" ? Parce que l'apprentissage préalable de 2-3 ans minimum n'est pas une contrainte peut-être ?
Cliquer sur un bouton c'est bien moins expressif... Parce que c'est ça l'objectif premier d'un programme ? Être "expressif" ??? 🤦♀️
Je cherche à comprendre comment charger le navigateur embarqué de Java FX dans un client lourd. Je ne sais pas si ce projet fonctionne mais ce sera un premier pas vers l'obtention d'un PoC qui marche.
Je suis tombée sur cet autre repo qui a deux avantages :
- Il va droit au but en affichant un index.html
- Il s'appuie sur les modules de Java 9+
Je suis tombée sur ce site par hasard. L'auteur qualifie les Data classes de code smell, dit autrement, les DTO et Entity seraient des code smells.
Je ne pouvais qu'être d'accord ! Quant au reste des propositions, elles collent plutôt bien à ce que mon expérience me fait penser aujourd'hui.
Je dois refaire du front depuis la semaine dernière et c'est bien moins facile que dans mon souvenir.
Ici, un post sur SOF qui explique comment séparer ses CSS de sorte à limiter les impacts lors des refactos, et faciliter la maintenance et évolutions (e.g. créer des composants multi-thèmes).
Comment charger du code WASM dans un navigateur ?
// This is our recommended way of loading WebAssembly.
(async () => {
const fetchPromise = fetch('fibonacci.wasm');
const { instance } = await WebAssembly.instantiateStreaming(fetchPromise);
const result = instance.exports.fibonacci(42);
console.log(result);
})();Je dois écrire un µ-service en Rust et j'ai cherché pas mal de serveurs web permettant de le faire. Évidemment, la première chose que les moteurs de recherche nous remontent c'est Hyper. Pour faire simple, Hyper est une serveur HTTP 1/2 qui s'appuie sur le pool de threads asychrone Tokio.
Problème, Hyper reste assez bas niveau. Je recherchais donc quelque chose aux performances équivalentes mais bien plus simple d'utilisation et je suis tombée sur Actix qui à l'air de faire le café. Je regrette uniquement la reprise du annotation-driven-bullshit via les macros déclaratives mais en dehors de cela, tout va bien.
Exemple de hello world en Actix / Rust :
use actix_web::{get, web, App, HttpServer, Responder};
#[get("/")]
async fn index() -> impl Responder {
"Hello, World!"
}
#[get("/{name}")]
async fn hello(name: web::Path<String>) -> impl Responder {
format!("Hello {}!", &name)
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
HttpServer::new(|| App::new().service(index).service(hello))
.bind(("127.0.0.1", 8080))?
.run()
.await
}En un code d'exemple :
// use macro_rules! <name of macro>{<Body>}
macro_rules! add {
// macth like arm for macro
($a:expr,$b:expr) => {
// macro expand to this code
{
// $a and $b will be templated using the value/variable provided to macro
$a+$b
}
}
}
// Usage in code
fn main(){
// call to macro, $a=1 and $b=2
add!(1,2);
}
Attention à ne pas abuser de la méta-programmation car cela peut augmenter significativement les temps de compilation.
Article vraiment très bien proposé ici par @Sebsauvage.
On se rapproche très fortement de ce que propose David West dans Object Thinking (livre qui a 20 ans déjà) et Yegor Bugayenko dans Elegant Objects (livre qui doit fêter ses 8/9 ans). Je me permets de compléter la solution de la pratique n° 3.
L'auteur propose d'encapsuler la hauteur dans une entité, ce qui nous donne :
// Primitive contenue dans un objet (aussi appelé Value Object)
class ArticleHeight {
private value: number;
constructor(value: number) {
if (value < 10) {
throw new HeightCanNotBeLessThanTen();
}
if (value > 100) {
throw new HeightCanNotBeGreaterThan100();
}
this.value = value;
}
}
// passage de notre ArticleHeight dans le constructor
class Article {
private height: ArticleHeight;
constructor(height: ArticleHeight) {
this.height = height;
}
}
// eh voilou !
class AddArticleUsecase {
execute({ height }) {
//...
const article = new Article(new ArticleHeight(height));
//...
}
}
Pas moi. Je propose que la classe Article s'attende à recevoir en paramètre une interface Height dont l'une des implémentations possible soit une ArticleHeight mais qui pourrait très bien être une valeur venant d'une BDD au moyen d'une HeightFromBdd (pas le meilleur nom, mais c'est pour représenter l'idée).
Ceci casse le couplage entre deux classes concrètes et subséquemment facilite les mocks/stubs durant les tests dont l'auteur ne parle pas.
Ce qui nous donne
// Primitive contenue dans un objet (aussi appelé Value Object)
interface Height {
value(): number
}
class ArticleHeight implements Height {
private value: number;
constructor(value: number) {
if (value < 10) {
throw new TooShortLength("Un article doit faire au minium 10 lignes");
}
if (value > 100) {
throw new TooLongLength("Un article ne peut faire plus de 100 lignes");
}
this.value = value;
}
value(): number {
return this.value;
}
}
class Article {
private height: Height;
constructor(height: Height) {
this.height = height;
}
}
class AddArticleUsecase {
execute({ height }) {
//...
const article = new Article(new ArticleHeight(height));
//...
}
}
Et sur le même modèle, si votre classe expose une méthode publique, c'est qu'elle est imposée par une interface, dans tous les autres cas de figure les méthodes qui ne viennent pas d'interfaces doivent être privées.
Ce serait la 10ème règle que j'ajouterais à l'article.
Les observateurs auront aussi remarqué que j'ai changé les exceptions. Il ne vaut pas confondre nom de l'exception et contexte dans lequel une erreur été levée. D'où l'importance d'un message qui exprime la raison d'une erreur et le nom de l'exception qui exprime le type d'erreur remontée.
Ajouter des contraintes sur les imports Java/Kotlin depuis le plugin maven enforcer.
Edit : la solution ne marche pas. J'en recherche une autre à la place.
Quelque propose
@Inject
@Nullable
private SomeBean someBean;
Je ne sais pas s'il s'agit des Annotations JetBrains ou de la lib JSR de FindBugs.
Si vous êtes sur Java 8 ou plus (rappel, la dernière version LTS est Java 17, si vous êtes encore sous Java 8 / 11 vous êtes en retard) alors vous pouvez remplacer :
@Autowired(required = false)
private SomeBean someBean;
Par ceci :
@Inject
private Optional<SomeBean> someBean;
Le but étant pour moi de sortir plusieurs projets de Spring, il faut donc y aller par petits bouts, en commençant par remplacer les annotations de Spring.
En un exemple court et simple :
package com.memorynotfound;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
public class GetUpTime {
public static void main(String... args) throws InterruptedException {
RuntimeMXBean rb = ManagementFactory.getRuntimeMXBean();
System.out.println("Up time: " + rb.getUptime() + " ms");
}
}