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");
}
}
Exemple d'utilisation des tests paramétrés en TestNG avec les DataProvider :
import static org.assertj.core.Asserstions.assertThat;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;
public class ExempleTest {
private PrimeNumberChecker primeNumberChecker = new PrimeNumberChecker();
@DataProvider(name = "test1")
static Object[][] primeNumbers() {
return new Object[][] {{2, true}, {6, false}, {19, true}, {22, false}, {23, true}};
}
// This test will run 5 times since we have 5 parameters defined
@Test(dataProvider = "test1")
void testPrimeNumberChecker(Integer inputNumber, Boolean expectedResult) {
assertThat(primeNumberChecker.validate(inputNumber)).isEqualTo(expectedResult);
}
}
J'ai vécu une phase comme ça, entre 2014 et 2016 où ça devenait penible pour moi de coder. J'avais même accepté un job de chef de projet en 2015 c'est dire ! À cette époque, j'avais l'impression d'avoir fait le tour de la question, toutes les applications avaient tout le temps les mêmes couches, avec les mêmes frameworks et systématiquement le code technique et les classes anémiques prédominaient.
Puis j'ai redécouvert la programmation fonctionnelle (la vraie, pas celle de Java) mais aussi la programmation orientée objets (la vraie aussi, pas celle de Java) alors que j'étais pourtant sûr et certaine de maîtriser l'une et l'autre.
J'ai alors accepté l'idée que je ne savais coder ni dans l'une ni dans l'autre et que tout ce qui m'était présenté comme des "patterns" embarqués out-of-the-box par des frameworks comme Spring Boot étaient en réalité des anti-patterns et souvent parmi les pires !
J'ai commencé à détester coder à cette époque parce que le code était devenu une procédure à dérouler dans une architecture normée, pensée et plébiscitée par des non-développeurs que le marché appelait "architectes" et cela m'ôtait toute possibilité de réfléchir à comment faire et surtout de faire mieux que ces tripotés d'ingénieurs-cadres hélicoptères ne sachant plus trier une liste.
Ce qui m'a redonner l'envie de coder ce fût la découverte de Kotlin en 2015, de Yegor Bugayenko à la même époque et les cours de Kysofer qui a passé des week-ends entiers à me faire découvrir tout un tas de choses notamment :
- Pourquoi et en quoi l'API stream de Java 8 n'était pas du tout de la programmation fonctionnelle.
- Pourquoi je n'avais jamais créé ni utilisé le moindre objet au sens OOP du terme avec JPA ou des DTO.
- En quoi la composition vs héritage n'était pas du tout ce que je pensais et ce qu'internet disait.
- Pourquoi si j'avais du mal à écrire des tests c'était à cause des architectures procédurales et qu'en réalité c'était facile et que j'adorais ça.
- En quoi écrire la doc était une perte de temps mais était obligatoire à cause des architectures orientées techniques et non métier.
Et tellement d'autres choses. @Kysofer tu avais raison quand tu me disais : " j'adore mon métier, mais je déteste mon travail ".
Bref si vous ne codez plus, quittez l'IT, les meilleurs entraîneurs sont ceux qui ont boxé jusqu'au bout, pas ceux qui n'ont fait ca que 4 ou 5 ans.
Merci à @Philou qui associe cette hypothèse tirée de la sociologie à la façon tristement commune de gérer les problèmes dans du code.
@Oros j'ai souvent vu que la ligne set -euo pipefail
était recommandée en Bash et je voudrai te poser une question car je crois que le c'est le -e
ou le pipefail
qui ne marchent pas chez moi à cause de ma façon de coder en Bash.
En fait (et je sais que @Animal fait pareil) je créé des fichiers à sourcer et qui ne contiennent que des fonctions. Ces fichiers/bibliothèques peuvent aussi contenir des constantes via un export -r
et surtout, chaque fonction est testée unitairement avec bbtools ou shellunit.
Comme Bash ne permet que de retourner des "exit codes" depuis une fonction, le hack consiste à leur faire imprimer le résultat souhaité via un echo
unique et d'exécuter la fonction de la manière suivante pour récupérer la valeur de retour :
local resultat
resultat=$(ma_fonction "${param_eventuel}")
Donc mon script principale consiste à sourcer les libs dans le bon ordre puis à déclencher une fonction unique, en générale baptisée main()
qui contient la procédure à suivre. Évidemment, cette fonction main()
est purement déclarative et se limite à déléguer les traitements aux fonctions des API sourcées.
Est-ce que tu procèdes comme ça pour écrire un script où est-ce que tu écris les traitements en flat directement dedans ? (Je vais essayer de retrouver le cas ou le set -euo pipefail
plante avec des fonctions)
Si vous codez dans un langage à destination d'une JRE (Kotlin, Java, Scala, Groovy, etc) vous avez sûrement entendu parler de Spring Boot. Pour ce qui ne le connaissent pas, c'est LE framework qui est parti de rien (à l'origine c'était seulement Spring Framework), puis qui a grossi tout doucement depuis 15 ans et est devenu aujourd'hui un mastodonte aussi gros, lourd, pénible et lent à démarrer que l'ancien JEE (avec des Websphere et Weblogic, etc).
Mais en réalité est-ce que c'est mal ?
Pas vraiment, Spring Boot pousse à produire du code en couche avec des singletons présents partout à chaque couche. Ce n'est pas comme cela que l'on écrit du code concis, découplé, court et maintenable, mais ça a le mérite de s'écrire vite, d'être simple pour des débutants et de fonctionner quand même (en tout cas au début). Après c'est un enfer à tester en terme d'écriture et de temps d'exécution mais bon, qui teste encore son code en 2021 ? #Sadness
Alors quel est mon problème ?
Mon problème c'est que parmi l'ensemble des développements actuels auxquels je contribue chez mes clients, ceux-ci sont couplés totalement à Spring Boot. Vous montez de version, vos développements risquent de péter, vous souhaitez quitter Spring Boot pour autre chose de plus rapide comme Quarkus, pas possible les libs ont été codées pour Spring Boot, d'ailleurs pour les utiliser aucune lib ne pourra se charger si vous n'avez pas Spring Boot car seul Spring Boot doit être en mesure de les instancier. #Folie
Et c'est ça mon problème, Java avait supprimé la problématique de nettoyage de la mémoire, Spring Framework avait supprimé la problématique de création des instances et Spring Boot supprime aujourd'hui la notion d'architecture (ce qui n'a pas du tout le même impact puisque ça touche à la capacité d'innover et de faire différemment), or un code propre qui soit fonctionnel et objet requiert la création et la destruction permanente d'instances immutables à cycle de vie ultra court (une action puis poubelle), ce qui est l'antithèse même des singletons omniprésents, paramétrés par AOP (ndr. Aspect Oriented Programming) et poussés par Spring...
En synthèse :
Pour toutes ces raisons, Spring Boot va à mon sens à contre courant des meilleures pratiques de développement connues et reconnues à cette heure parce qu'il préserve les façons de coder d'il y a plus de 20 ans et venant de langages ni objets ni fonctionnels comme le C, pire encore les "développeurs Spring Boot" sont tellement à fond dans Spring Boot qu'ils n'arrivent même plus à penser leurs libs comme des éléments qui puissent s'utiliser en dehors de Spring Boot et c'est ce qui me fait dire que Spring Boot est un contre-choix et une fausse-bonne idée.
Je découvre le mot-clef expect
de Kotlin. Son objectif est de dire que pour une même classe, il va y avoir différentes implémentations en fonction de la plateforme.
Par exemple pour la classe (vide) :
expect class KMPDate(formatString: String) {
fun asString(): String
}
Nous aurons cette première implémentation pour Android :
actual class KMPDate actual constructor(formatString: String) { // 1
private val dateFormat = SimpleDateFormat(formatString) // 2
actual fun asString(): String {
return dateFormat.format(Date()) // 3
}
}
et cette seconde pour iOS :
actual class KMPDate actual constructor(formatString: String) { // 1
private val dateFormatter = NSDateFormatter().apply { // 2
this.dateFormat = formatString
}
actual fun asString(): String {
return formatter.stringFromDate(NSDate()) // 3
}
}
KPMDate n'est pas une interface mais bien une classe concrète avec plusieurs implémentions dites "platform-dependent" dans le même fichier.
Mieux encore, c'est compatible avec GraalVM et Kotlin native pour produire des binaires natifs (AMD64 et ARM64 principalement) compilés et linkés statiquement (+ compilation AOT + tree shaking pour les optims) sans avoir besoin d'une JRE d'installée sur l'environnement cible, donc parfait dans des conteneurs très légers par exemple :D