OVH Cloud OVH Cloud

Microsoft et Java

295 réponses
Avatar
Wykaaa
Microsoft semble reconnaître que Java permet de développer plus
rapidement que C# et qu'il y a moins de failles de sécurité dans Java
que dans .net :
http://dsi.silicon.fr/nouveautes/microsoft-java-forever%E2%80%A6-1366

10 réponses

Avatar
Toxico Nimbus
Le 20/06/2011 08:55, JKB a écrit :

Écoute, tu peux être convaincu que les exceptions sont le meilleur
traitement possible d'une erreur. C'est ton droit. Je pense pour ma
part que ce truc est le pire des traitements d'erreur parce qu'il
s'appuie sur tout un tas de choses y compris le GC. C'est une
aberration totale parce qu'on n'a pas envie que le développe sache
(faire) une gestion propre et efficace qui est un peu plus complexe.



[SNIP]

Les exceptions, c'est bien
lorsque tu as un petit programme dans un coin. Lorsque tu as un truc
énorme, c'est une monumentale connerie.



En somme ce qui te gêne dans les exceptions, c'est le garbage collector
et les mauvaises pratiques des devs Java ?


Tu peux définir techniquement "totalement dégueulasse" ?



Récupérer à l'endroit où on peut réellement traiter l'erreur (soit
beaucoup plus haut dans la pile) une exception générique. C'est
idiot et la syntaxe java consiste à mettre des gestionnaires
d'exception un peu partout, renvoyer l'exception au père, grand'père
ou arrière-grand'père voire pire par un throw. Le seul moyen de gérer
correctement une erreur est de la remonter le long de la pile en la
gérant à chaque appel de fonction.



Non, la syntaxe Java permet tout à fait de gérer les exceptions ligne
par ligne, c'est même la seule manière propre de faire et c'est
rigoureusement identique au test d'un code d'erreur du C, à la gestion
de la mémoire près.

--
Toxico Nimbus
Avatar
Yliur
> Et donc en général en Java ça se résume à rien, parce qu'on ne
> libère pas la mémoire explicitement. La plupart des fonctions n'ont
> pas d'autres ressources à libérer (connexions, fichiers, ...), et
> donc on ne fait quelque chose que dans ces fonctions.

Ça, c'est parce que tu n'en as rien à faire. Appelle un peu
le GC à la main sur une application serveur écrite en Java, et tu vas
voir qu'il est particulièrement inefficace.



?
Tu veux dire qu'il est lent ? Ou qu'il ne fait pas son boulot
correctement ?

>> >> puis de remonter l'erreur (soit avec un code
>> >> d'erreur, soit avec une exception et un magnifique throw)
>> >
>> > S'il n'y a pas de catch mais seulement un finally, il n'y a même
>> > pas besoin de propager l'exception : le code de nettoyage dans
>> > le bloc finally est exécuté puis l'exception est automatiquement
>> > propagée.
>>
>> Impossible à faire dans le cas général.
>
> Pourquoi ? Si l'exception doit être traitée explicitement
> (IOException par exemple), c'est vrai, mais on l'emballe dans une
> exception propre à l'appli qui n'est pas vérifiée par exemple, qui
> remontera facilement la pile d'appels.

Toi, il y a longtemps que tu n'as pas vu un vrai code qui
doit être prêt pour la semaine dernière. Le dev java, quand il est à
la bourre, il ne _fait_ pas ça. Il te colle d'emblée un gros
gestionnaire d'exception bien sale qui récupère tout pour ne
pas s'emmerder lors du développement.



Quand il est à la bourre, il ne colle pas d'emblée des trucs, il attend
que le compilateur vienne geindre : "ouin, mais t'as pas capturé ces
exceptions".

Pour ce qui est de la remontée des exceptions : dans le cas que je
prends comme exemple tu es obligé de le mettre dans la fonction. Donc
tu peux récupérer tout en vrac si ça te chante, et emballer l'exception
dans une exception non vérifiée est une des solutions les plus simples
qui se présentent. Je ne vois pas pourquoi le développeur à la bourre
choisirait subitement autre chose.

Est-ce que quand le développement C est à la bourre, le développeur C
fait appel à ses pouvoirs magiques (divins), une grande lumière descend
du ciel et l'aide à travailler deux fois plus vite pour faire à la main
et correctement toutes les vérifications d'erreur et toute la libération
de la mémoire ?


Écoute, tu peux être convaincu que les exceptions sont le
meilleur traitement possible d'une erreur. C'est ton droit.



Ah bon... je croyais que c'était une discussion argumentée.

Je pense
pour ma part que ce truc est le pire des traitements d'erreur parce
qu'il s'appuie sur tout un tas de choses y compris le GC.



On peut lister les choses ? Ça peut être intéressant pour comprendre en
quoi c'est gênant.


C'est une
aberration totale parce qu'on n'a pas envie que le développe
sache (faire) une gestion propre et efficace qui est un peu plus
complexe. J'ai sous le coude une application Java, à peu près écrite
correctement qui fonctionne sur une architecture trois tiers
en réseau. À chaque fois qu'il y a un paquet qui passe à la trappe ou
une session utilisateur qui se bauge, les erreurs sont
récupérées, mais il faut un temps certain pour que le GC libère la
mémoire associée et un appel à la main peu libérer plusieurs
centaines de Mo !



Et... ?

Tiens, rien à voir, mais on peut en faire des trucs amusants. J'ai vu
des gens expliquer comment avec beaucoup de mémoire pour la JVM on
pouvait la lancer en mode "optimisations agressives" : le collecteur de
mémoire ne s'occupe pas de récupérer de la mémoire avant qu'il n'y en
ait plus de disponible (au moins tant qu'il y a autre chose à
exécuter). Donc si l'appli n'a pas besoin d'être sur pied 100% du
temps on peut décider au moment de la lancer de la laisser goinfrer la
mémoire puis l'éteindre et la relancer pour éviter le temps passer à
récupérer la mémoire.


Résultat des courses, toutes les erreurs sont gérés
à la C, proprement, car la gestion par exception faisait juste
planter la JVM sur un 'out of memory exception' !



On pourrait avoir le code incriminé avant d'attribuer ça aux
exceptions ou au ramasse-miettes ? Le collecteur de mémoire est
censé récupérer la mémoire quand elle n'est plus utilisée (et qu'il
n'a rien à faire ou qu'il a besoin de mémoire ailleurs par exemple),
donc il n'y a pas de lien entre le fait qu'il la récupère par gros
paquets et le fait qu'il en manque.

>> Dans le cas où il a des choses à récupérer (fichiers, ...), en
>> général il y a une exception à gérer explicitement
>> (IOException, ...). Donc l'obligation de réfléchir à ce qu'il faut
>> en faire (moins facile à oublier qu'un code d'erreur).


>>
>> Sauf que c'est très con. Parce que ton exception peut être
>> récupérée tout à fait ailleurs
>
> Comment ça ? La méthode qui fait l'appel concerné est obligée de
> traiter l'exception localement ou de la laisser passer
> explicitement. L'exception n'apparaît pas miraculeusement ailleurs.

Tu n'as pas l'impression de te prendre les pieds dans le
tapis ? Tu disais plus haut qu'on ne savait pas localement comment
prendre une décision et qu'il fallait que ça remonte. Il y a une
contradiction dans les termes.



Ce n'est pas parce qu'elle remonte qu'elle apparaît miraculeusement
ailleurs. Et les codes d'erreurs de tes fonctions C remontent aussi, je
ne vois pas la différence.

L'appli ne sait en général pas quoi faire de l'erreur localement (quel
que soit le système) : elle ne sait que libérer des ressources et faire
remonter l'erreur. Donc sur le chemin il faut tout libérer. En C ça
consiste à écrire dans toutes les fonctions du code de gestion des
erreurs et de libération de la mémoire. En Java ça consiste simplement
à écrire un try/finally autour du code gérant certaines ressources
(fichiers, ...), le reste du temps la mémoire n'est pas gérée à
la main. Donc il n'y a pas besoin de remplir le code de gestion
d'erreurs, il suffit de se concentrer sur les points où ces ressources
sont manipulées.

L'appli sait en général "traiter" l'erreur à plus haut niveau : il
s'agit de remonter l'erreur le plus précisément possible et de décider
de la politique de gestion des erreurs (si tel traitement plante,
qu'est-ce que je fais ?). Je ne vois pas la différence entre les codes
d'erreur et les exceptions pour ça (à part que les exceptions sont des
objets faciles à remonter et qui peuvent contenir facilement beaucoup
d'information).

>> et de façon totalement dégueulasse.
>
> Tu peux définir techniquement "totalement dégueulasse" ?

Récupérer à l'endroit où on peut réellement traiter l'erreur
(soit beaucoup plus haut dans la pile) une exception générique.



C'est normal de la traiter à cet endroit.

C'est
idiot et la syntaxe java consiste à mettre des gestionnaires
d'exception un peu partout,



Non.

renvoyer l'exception au père,
grand'père ou arrière-grand'père voire pire par un throw.



En quoi c'est pire ?

Le seul
moyen de gérer correctement une erreur est de la remonter le long de
la pile en la gérant à chaque appel de fonction.



L'exception remonte effectivement la pile. Et il n'y a que quelques
points où il y a réellement besoin de la traiter, contrairement au C.
Donc au lieu d'étaler partout du code de gestion de la mémoire qui doit
être gérée à la main partout (et qui *oblige* à une gestion pas à pas de
l'erreur), on s'en dispense en Java et on ne gère les exceptions que
dans le cas de la libération de certaines ressources (il y en a assez
peu).
Avatar
totof01
On 18 juin, 18:22, Aéris wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 18/06/2011 18:09, JKB a écrit :

>> Parce que même en testant le code de retour, 99% des développeurs ne
>> > savent de toute façon pas comment gérer l'erreur, et encore moin s
>> > proprement.
>    Tu te rends compte que tu rajoutes de l'eau à mon moulin ? Dep uis
>    longtemps, je pense que Java est un truc permettant à des
>    programmeurs mauvais de pisser du code (jetable) et tu abondes d ans
>    mon sens.

Qu'on soit en C ou en Java, un mauvais développeur fera autant d'erreur .
Sauf qu'en C le résultat sera rapidement catastrophique, alors qu'en
Java pas mal de gardes-fous existent.



Autrement dit : en C tu te rends compte de suite que tu as affaire à
une tanche. En Java, il peut se passer des mois ou des années pour que
le truc t'explose à la figure, et entre temps le dev en question a
donné sa dem, et tu ne sais pas exactement ce qui cause problème. Tu
en es donc réduit à "exiger" de tes clients une version précise d'OS,
de service pack ou de noyau, de JVM, de libs, etc ... pour pas que
l'appli se vautre
Avatar
totof01
On 18 juin, 18:50, Aéris wrote:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Le 18/06/2011 18:25, JKB a écrit :

>    Si, tu le sais parfaitement. Les fonctions de la libc (et de la
>    plupart des bibliothèques) te renvoient une erreur et un code
>    d'erreur dans errno.

Donc je vais blinder mon code de errno (théoriquement 1 ligne sur 2)
pour ensuite le farcir de if ( error == MaLib.SEG_FAULT ) … else if (
error == MaLib.FOO_ERROR ) ?
Pire encore, ma propre fonction va devoir propager cette erreur à
l'appelant, donc aussi devoir gérer errno, la valeur de retour, avec
encore plus de if/else et de return partout, et l'appelant devrait aussi
faire un if -1, un appel à errno, une platré de if/else pour se
rattraper et une platré de gestion de errno en cas de non récupérat ion
pour ensuite propager à l'appellant qui devra…………

T'appelles ça du code propre toi ?

> Tu sais donc parfaitement pourquoi ça a planté
>    lorsque tu peux avoir une ambiguité. On n'a vraiment pas dû
>    apprendre le C au même endroit...

Euh pas exactement au même endroit je pense =)
Mais on a donc bien vu les mêmes codes tout bloated de gestion et de
propagation d'erreurs avec des chiés de #define dans les .h, des platr és
de if/elif, de return dans tous les coins, de tricks à la con pour
pouvoir à la fois faire un return « métier » et un return « err eur »
(ben oui, si ma méthode devait déjà retourner quelque chose, je fai s
comment pour retourner -1 ou le code d'erreur ?)

>    Et alors ? La récupération peut être aussi bête que ne p as faire
>    planter le programme sur une erreur de segmentation.

Utilité ?
« Votre programme a planté. Mais ceci n'est pas un segfault »

Je préfère de loin le « Segmentation fault : null pointer dereferen ce in
toto.so:38 », au moins j'ai de quoi tracker l'erreur…



Imagine que ton code est chargé de gérer le déplacement d'une machine -
outil, et que ton malloc se vautre alors que tu es en train de faire
un positionnement en vitesse rapide de ton outil. Il serait plus
judicieux de couper les moteurs de déplacement de ton outil avent de
se vautrer non ? Si tu laisses un segfault se produire avant de couper
ton moteur, et que tu attaques la matiere en vitesse rapide, ça risque
d'être drole.
Avatar
JKB
Le Mon, 20 Jun 2011 12:32:43 +0200,
Toxico Nimbus écrivait :
Le 20/06/2011 08:55, JKB a écrit :

Écoute, tu peux être convaincu que les exceptions sont le meilleur
traitement possible d'une erreur. C'est ton droit. Je pense pour ma
part que ce truc est le pire des traitements d'erreur parce qu'il
s'appuie sur tout un tas de choses y compris le GC. C'est une
aberration totale parce qu'on n'a pas envie que le développe sache
(faire) une gestion propre et efficace qui est un peu plus complexe.



[SNIP]

Les exceptions, c'est bien
lorsque tu as un petit programme dans un coin. Lorsque tu as un truc
énorme, c'est une monumentale connerie.



En somme ce qui te gêne dans les exceptions, c'est le garbage collector
et les mauvaises pratiques des devs Java ?



Pas exactement. Ce qui me pose problème, c'est la rigidité du 'je
suis obligé de coller un gestionnaire d'exception, sauf que là, je
n'ai pas le temps, et comme je ne veux pas m'emmerder, je colle un
gestionnaire générique qui ne fait rien parce que ça ira bien'.

Tu peux définir techniquement "totalement dégueulasse" ?



Récupérer à l'endroit où on peut réellement traiter l'erreur (soit
beaucoup plus haut dans la pile) une exception générique. C'est
idiot et la syntaxe java consiste à mettre des gestionnaires
d'exception un peu partout, renvoyer l'exception au père, grand'père
ou arrière-grand'père voire pire par un throw. Le seul moyen de gérer
correctement une erreur est de la remonter le long de la pile en la
gérant à chaque appel de fonction.



Non, la syntaxe Java permet tout à fait de gérer les exceptions ligne
par ligne, c'est même la seule manière propre de faire et c'est
rigoureusement identique au test d'un code d'erreur du C, à la gestion
de la mémoire près.



Ah, tu vois, finalement, tu es d'accord avec moi. Et dans ce cas,
l'exception n'apporte rien puisque l'intérêt de l'exception est
justement de ne pas gérer les erreurs ligne après ligne.

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
JKB
Le Mon, 20 Jun 2011 13:33:45 +0200,
Yliur écrivait :

> Et donc en général en Java ça se résume à rien, parce qu'on ne
> libère pas la mémoire explicitement. La plupart des fonctions n'ont
> pas d'autres ressources à libérer (connexions, fichiers, ...), et
> donc on ne fait quelque chose que dans ces fonctions.

Ça, c'est parce que tu n'en as rien à faire. Appelle un peu
le GC à la main sur une application serveur écrite en Java, et tu vas
voir qu'il est particulièrement inefficace.



?
Tu veux dire qu'il est lent ? Ou qu'il ne fait pas son boulot
correctement ?



Qu'il réagit et libère la mémoire avec beaucoup de retard. Quand
dans une application, un appel explicite au GC te libère d'un seul
coup 50% de la mémoire utilisée, c'est qu'il est mauvais.

>> >> puis de remonter l'erreur (soit avec un code
>> >> d'erreur, soit avec une exception et un magnifique throw)
>> >
>> > S'il n'y a pas de catch mais seulement un finally, il n'y a même
>> > pas besoin de propager l'exception : le code de nettoyage dans
>> > le bloc finally est exécuté puis l'exception est automatiquement
>> > propagée.
>>
>> Impossible à faire dans le cas général.
>
> Pourquoi ? Si l'exception doit être traitée explicitement
> (IOException par exemple), c'est vrai, mais on l'emballe dans une
> exception propre à l'appli qui n'est pas vérifiée par exemple, qui
> remontera facilement la pile d'appels.

Toi, il y a longtemps que tu n'as pas vu un vrai code qui
doit être prêt pour la semaine dernière. Le dev java, quand il est à
la bourre, il ne _fait_ pas ça. Il te colle d'emblée un gros
gestionnaire d'exception bien sale qui récupère tout pour ne
pas s'emmerder lors du développement.



Quand il est à la bourre, il ne colle pas d'emblée des trucs, il attend
que le compilateur vienne geindre : "ouin, mais t'as pas capturé ces
exceptions".

Pour ce qui est de la remontée des exceptions : dans le cas que je
prends comme exemple tu es obligé de le mettre dans la fonction. Donc
tu peux récupérer tout en vrac si ça te chante, et emballer l'exception
dans une exception non vérifiée est une des solutions les plus simples
qui se présentent. Je ne vois pas pourquoi le développeur à la bourre
choisirait subitement autre chose.

Est-ce que quand le développement C est à la bourre, le développeur C
fait appel à ses pouvoirs magiques (divins), une grande lumière descend
du ciel et l'aide à travailler deux fois plus vite pour faire à la main
et correctement toutes les vérifications d'erreur et toute la libération
de la mémoire ?



Il y a juste une différence. Le dev C, en général, est beaucoup plus
capé que le développeur Java parce que le langage est plus difficile
d'accès.

Écoute, tu peux être convaincu que les exceptions sont le
meilleur traitement possible d'une erreur. C'est ton droit.



Ah bon... je croyais que c'était une discussion argumentée.

Je pense
pour ma part que ce truc est le pire des traitements d'erreur parce
qu'il s'appuie sur tout un tas de choses y compris le GC.



On peut lister les choses ? Ça peut être intéressant pour comprendre en
quoi c'est gênant.



Sur la remontée des erreurs sur la pile (c'est justement l'intérêt
de l'exception).
Sur le GC pour libérer ce qui doit être libéré.
Sur le système d'interruption hard (ou une émulation de celui-ci).
Et c'est sans compter sur quelques interactions amusantes avec l'OS.

C'est une
aberration totale parce qu'on n'a pas envie que le développe
sache (faire) une gestion propre et efficace qui est un peu plus
complexe. J'ai sous le coude une application Java, à peu près écrite
correctement qui fonctionne sur une architecture trois tiers
en réseau. À chaque fois qu'il y a un paquet qui passe à la trappe ou
une session utilisateur qui se bauge, les erreurs sont
récupérées, mais il faut un temps certain pour que le GC libère la
mémoire associée et un appel à la main peu libérer plusieurs
centaines de Mo !



Et... ?

Tiens, rien à voir, mais on peut en faire des trucs amusants. J'ai vu
des gens expliquer comment avec beaucoup de mémoire pour la JVM on
pouvait la lancer en mode "optimisations agressives" : le collecteur de
mémoire ne s'occupe pas de récupérer de la mémoire avant qu'il n'y en
ait plus de disponible (au moins tant qu'il y a autre chose à
exécuter). Donc si l'appli n'a pas besoin d'être sur pied 100% du
temps on peut décider au moment de la lancer de la laisser goinfrer la
mémoire puis l'éteindre et la relancer pour éviter le temps passer à
récupérer la mémoire.



Et c'est intelligent ? Ce qui coûte cher, c'est l'allocation de la
mémoire, pas sa libération. Le GC est un truc qui n'est là que pour
obvier aux problèmes des développeurs infichus d'utiliser la mémoire
correctement.

En d'autres termes, que tu laisses ou non le GC faire son boulot
n'accélère pas l'allocation de la mémoire. Tu gagnes simplement des
pouillèmes lors de la libération.

Résultat des courses, toutes les erreurs sont gérés
à la C, proprement, car la gestion par exception faisait juste
planter la JVM sur un 'out of memory exception' !



On pourrait avoir le code incriminé avant d'attribuer ça aux
exceptions ou au ramasse-miettes ? Le collecteur de mémoire est
censé récupérer la mémoire quand elle n'est plus utilisée (et qu'il
n'a rien à faire ou qu'il a besoin de mémoire ailleurs par exemple),
donc il n'y a pas de lien entre le fait qu'il la récupère par gros
paquets et le fait qu'il en manque.



Le problème est qu'il fait ça quand ça lui chante.

>> Dans le cas où il a des choses à récupérer (fichiers, ...), en
>> général il y a une exception à gérer explicitement
>> (IOException, ...). Donc l'obligation de réfléchir à ce qu'il faut
>> en faire (moins facile à oublier qu'un code d'erreur).


>>
>> Sauf que c'est très con. Parce que ton exception peut être
>> récupérée tout à fait ailleurs
>
> Comment ça ? La méthode qui fait l'appel concerné est obligée de
> traiter l'exception localement ou de la laisser passer
> explicitement. L'exception n'apparaît pas miraculeusement ailleurs.

Tu n'as pas l'impression de te prendre les pieds dans le
tapis ? Tu disais plus haut qu'on ne savait pas localement comment
prendre une décision et qu'il fallait que ça remonte. Il y a une
contradiction dans les termes.



Ce n'est pas parce qu'elle remonte qu'elle apparaît miraculeusement
ailleurs. Et les codes d'erreurs de tes fonctions C remontent aussi, je
ne vois pas la différence.



Ils ne remontent pas par la pile et par un système d'interruption. Ils
remontent normalement par des variables explicites lors des retours de
fonction.

L'appli ne sait en général pas quoi faire de l'erreur localement (quel
que soit le système) : elle ne sait que libérer des ressources et faire
remonter l'erreur. Donc sur le chemin il faut tout libérer. En C ça
consiste à écrire dans toutes les fonctions du code de gestion des
erreurs et de libération de la mémoire. En Java ça consiste simplement
à écrire un try/finally autour du code gérant certaines ressources
(fichiers, ...), le reste du temps la mémoire n'est pas gérée à
la main. Donc il n'y a pas besoin de remplir le code de gestion
d'erreurs, il suffit de se concentrer sur les points où ces ressources
sont manipulées.



Et c'est justement ce qui fait que c'est mauvais. Si tu as une
petite application et 8 Go de mémoire, c'est peut-être efficace.
Autrement, c'est contre-productif.

L'appli sait en général "traiter" l'erreur à plus haut niveau : il
s'agit de remonter l'erreur le plus précisément possible et de décider
de la politique de gestion des erreurs (si tel traitement plante,
qu'est-ce que je fais ?). Je ne vois pas la différence entre les codes
d'erreur et les exceptions pour ça (à part que les exceptions sont des
objets faciles à remonter et qui peuvent contenir facilement beaucoup
d'information).



Euh... Comment dire... Non. Tu as au contraire moins d'information
parce qu'elle est moins fine. L'exception que tu récupères tout en
haut est une exception sur un ensemble de lignes de code (sinon, tu
utiliserais une gestion à la C). L'information sur ce qui s'est
passé réellement est difficile à extraire.

>> et de façon totalement dégueulasse.
>
> Tu peux définir techniquement "totalement dégueulasse" ?

Récupérer à l'endroit où on peut réellement traiter l'erreur
(soit beaucoup plus haut dans la pile) une exception générique.



C'est normal de la traiter à cet endroit.

C'est
idiot et la syntaxe java consiste à mettre des gestionnaires
d'exception un peu partout,



Non.



Ah bon ? Les try{} catch() que mon compilo m'impose ne sont pas
obligatoires ?

renvoyer l'exception au père,
grand'père ou arrière-grand'père voire pire par un throw.



En quoi c'est pire ?



Parce que ça saute des appels de fonction. Si tu ne vois pas la
différence entre les deux façons de faire, je ne puis rien pour toi.

Le seul
moyen de gérer correctement une erreur est de la remonter le long de
la pile en la gérant à chaque appel de fonction.



L'exception remonte effectivement la pile. Et il n'y a que quelques
points où il y a réellement besoin de la traiter, contrairement au C.
Donc au lieu d'étaler partout du code de gestion de la mémoire qui doit
être gérée à la main partout (et qui *oblige* à une gestion pas à pas de
l'erreur), on s'en dispense en Java et on ne gère les exceptions que
dans le cas de la libération de certaines ressources (il y en a assez
peu).



Et c'est exactement ce que je reproche aux exceptions.

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
Yliur
Ce qui me pose problème, c'est la rigidité du
'je suis obligé de coller un gestionnaire d'exception, sauf
que là, je n'ai pas le temps, et comme je ne veux pas m'emmerder, je
colle un gestionnaire générique qui ne fait rien parce que ça ira
bien'.



Quelle différence avec 'je suis obligé de coller une gestion
d'erreur, sauf que là, je n'ai pas le temps, et comme je ne veux pas
m'emmerder, je ne fais rien parce que ça ira bien' ?
Avatar
Yliur
> Qu'on soit en C ou en Java, un mauvais développeur fera autant
> d'erreur. Sauf qu'en C le résultat sera rapidement catastrophique,
> alors qu'en Java pas mal de gardes-fous existent.
>
Autrement dit : en C tu te rends compte de suite que tu as affaire à
une tanche. En Java, il peut se passer des mois ou des années pour que
le truc t'explose à la figure, et entre temps le dev en question a
donné sa dem, et tu ne sais pas exactement ce qui cause problème. Tu
en es donc réduit à "exiger" de tes clients une version précise d'OS,
de service pack ou de noyau, de JVM, de libs, etc ... pour pas que
l'appli se vautre



Les sournoiseries peuvent mettre beaucoup de temps à apparaître, même
en C. Et plus c'est subtil (plus il y a de choses à maîtriser) et pire
c'est.

Si tu n'évalue pas un peu le niveau de tes développeurs, il y a un
problème à la base. Personne ne vérifie que le nouveau développeur ne
fait pas totalement n'importe quoi ?

Le niveau pour arriver à faire quelque chose qui marche à peu près
correctement (et du même niveau de qualité) est supérieur en C, c'est
tout. Ça te fait moins de gens capables de le faire (ou plus de
formation). La détection des gens qui sont en dessous du niveau ne se
fait pas plus facilement, ça ne fonctionne que si ton développeur ne
connaît vraiment rien à rien (et encore).
Avatar
JKB
Le Mon, 20 Jun 2011 15:09:11 +0200,
Yliur écrivait :
Ce qui me pose problème, c'est la rigidité du
'je suis obligé de coller un gestionnaire d'exception, sauf
que là, je n'ai pas le temps, et comme je ne veux pas m'emmerder, je
colle un gestionnaire générique qui ne fait rien parce que ça ira
bien'.



Quelle différence avec 'je suis obligé de coller une gestion
d'erreur, sauf que là, je n'ai pas le temps, et comme je ne veux pas
m'emmerder, je ne fais rien parce que ça ira bien' ?



C'est au contraire très différent. En C, tu écris une gestion des
erreurs volontairement. En Java, tu l'écris parce que sans, ça ne
compile pas. La différence est qu'avec Java, le dev de base commence
par écrire un méchant catch all en se disant qu'il peaufinera plus
tard, ce qui est rarement fait. La démarche n'est pas du tout la
même.

JKB

--
Si votre demande me parvient sur carte perforée, je titiouaillerai très
volontiers une réponse...
=> http://grincheux.de-charybde-en-scylla.fr
Avatar
Yliur
>> Ça, c'est parce que tu n'en as rien à faire. Appelle un peu
>> le GC à la main sur une application serveur écrite en Java, et tu
>> vas voir qu'il est particulièrement inefficace.
>
> ?
> Tu veux dire qu'il est lent ? Ou qu'il ne fait pas son boulot
> correctement ?

Qu'il réagit et libère la mémoire avec beaucoup de retard.
Quand dans une application, un appel explicite au GC te
libère d'un seul coup 50% de la mémoire utilisée, c'est qu'il est
mauvais.



Pourquoi ? La JVM avait peut-être bien mieux à faire avant. La mémoire
non libérée est quand même virtuellement disponible : en cas de manque,
le collecteur va venir la chercher.

Et si pour une raison ou une autre tu penses que tu sais mieux que la
JVM quand la récupération de la mémoire est souhaitable (tu sais
qu'entre deux opérations il va y avoir un moment à ne rien faire par
exemple), tu peux toujours la guider en demandant la collecte à ce
moment.


> Est-ce que quand le développement C est à la bourre, le développeur
> C fait appel à ses pouvoirs magiques (divins), une grande lumière
> descend du ciel et l'aide à travailler deux fois plus vite pour
> faire à la main et correctement toutes les vérifications d'erreur
> et toute la libération de la mémoire ?

Il y a juste une différence. Le dev C, en général, est
beaucoup plus capé que le développeur Java parce que le langage est
plus difficile d'accès.



Mais le langage est plus difficile, ce qui équilibre. Il y a plus de
trucs à gérer, c'est plus compliqué, pour arriver à faire des
programmes qui marchent aussi bien il faut une formation/pratique plus
grande. Le seul résultat c'est que tu te retrouves avec moins de
développeurs capables de faire le boulot.


>> Je pense
>> pour ma part que ce truc est le pire des traitements d'erreur parce
>> qu'il s'appuie sur tout un tas de choses y compris le GC.
>
> On peut lister les choses ? Ça peut être intéressant pour
> comprendre en quoi c'est gênant.

Sur la remontée des erreurs sur la pile (c'est justement
l'intérêt de l'exception).
Sur le GC pour libérer ce qui doit être libéré.
Sur le système d'interruption hard (ou une émulation de
celui-ci). Et c'est sans compter sur quelques interactions amusantes
avec l'OS.



Bon, maintenant qu'on a la liste, on peut savoir en quoi c'est gênant ?
Enfin les deux premiers points ont déjà l'air en cours de discussion, si
je comprends bien ce que tu dis...


>> C'est une
>> aberration totale parce qu'on n'a pas envie que le
>> développe sache (faire) une gestion propre et efficace qui est un
>> peu plus complexe. J'ai sous le coude une application Java, à peu
>> près écrite correctement qui fonctionne sur une architecture trois
>> tiers en réseau. À chaque fois qu'il y a un paquet qui passe à la
>> trappe ou une session utilisateur qui se bauge, les erreurs sont
>> récupérées, mais il faut un temps certain pour que le GC libère la
>> mémoire associée et un appel à la main peu libérer plusieurs
>> centaines de Mo !
>
> Et... ?



Ben c'était là qu'il fallait répondre.

> Tiens, rien à voir, mais on peut en faire des trucs amusants. J'ai
> vu des gens expliquer comment avec beaucoup de mémoire pour la JVM
> on pouvait la lancer en mode "optimisations agressives" : le
> collecteur de mémoire ne s'occupe pas de récupérer de la mémoire
> avant qu'il n'y en ait plus de disponible (au moins tant qu'il y a
> autre chose à exécuter). Donc si l'appli n'a pas besoin d'être sur
> pied 100% du temps on peut décider au moment de la lancer de la
> laisser goinfrer la mémoire puis l'éteindre et la relancer pour
> éviter le temps passer à récupérer la mémoire.

Et c'est intelligent ? Ce qui coûte cher, c'est l'allocation
de la mémoire, pas sa libération.



Là c'était un truc pas très important, qui me passait par la tête (pour
les développeurs Java plutôt), comme je l'indiquais.


Le GC est un truc qui n'est là que
pour obvier aux problèmes des développeurs infichus d'utiliser la
mémoire correctement.



Phrase de vieux con (désolé mais bon...).
Considérer que les outils pour simplifier le développement (ou quoi que
ce soit dans ce que les humains produisent) sert juste aux guignols qui
ne savent pas faire ça "comme les vrais" est historiquement idiot. Oui,
des outils qui simplifient la construction de couches supérieures çà
peut avoir des inconvénients, oui ça permet à plus de gens de
travailler dans le domaine, sans avoir à tout connaître (ce qui a
un avantage évident), mais les réduire à leurs inconvénients sans voir
les avantages c'est juste une phrase traditionnelle des vieux vers les
jeunes (pour simplifier un peu) : "pfff... de notre temps on savait
faire correctement". C'est rigolo mais ça néglige complètement les
questions de productivité, de quantité de main d'oeuvre
nécessaire/disponible, de complexité croissante (des logiciels par
exemple), ... C'est défendre l'artisanat contre l'industrie en disant :
"bah c'est tout pourri" (ben merci pour la subtilité). Oui, il peut y
avoir des avantages à l'artisanat et des inconvénients à l'industrie,
mais nier en vrac les avantages de l'industrialisation en terme de
productivité, de fiabilité, ... c'est légèrement un petit peu n'importe
quoi.


>> Résultat des courses, toutes les erreurs sont gérés
>> à la C, proprement, car la gestion par exception faisait juste
>> planter la JVM sur un 'out of memory exception' !
>
> On pourrait avoir le code incriminé avant d'attribuer ça aux
> exceptions ou au ramasse-miettes ? Le collecteur de mémoire est
> censé récupérer la mémoire quand elle n'est plus utilisée (et qu'il
> n'a rien à faire ou qu'il a besoin de mémoire ailleurs par exemple),
> donc il n'y a pas de lien entre le fait qu'il la récupère par gros
> paquets et le fait qu'il en manque.

Le problème est qu'il fait ça quand ça lui chante.



Je ne vois pas le rapport avec ton erreur de mémoire : il fait ça quand
ça lui chante ou quand il en a besoin.


> L'appli ne sait en général pas quoi faire de l'erreur localement
> (quel que soit le système) : elle ne sait que libérer des
> ressources et faire remonter l'erreur. Donc sur le chemin il faut
> tout libérer. En C ça consiste à écrire dans toutes les fonctions
> du code de gestion des erreurs et de libération de la mémoire. En
> Java ça consiste simplement à écrire un try/finally autour du code
> gérant certaines ressources (fichiers, ...), le reste du temps la
> mémoire n'est pas gérée à la main. Donc il n'y a pas besoin de
> remplir le code de gestion d'erreurs, il suffit de se concentrer
> sur les points où ces ressources sont manipulées.

Et c'est justement ce qui fait que c'est mauvais. Si tu as une
petite application et 8 Go de mémoire, c'est peut-être
efficace. Autrement, c'est contre-productif.



Tu répètes toujours ça en bougonnant parce que le collecteur ramasse la
mémoire quand ça lui chante plutôt que quand toi tu le décides à la
main de vrai développeur avec qui on ne la fait pas, mais tu te gardes
d'expliquer précisément en quoi c'est "contre-productif". De quel point
de vue ? Elle est quand même récupérée ta mémoire, non ?



> L'appli sait en général "traiter" l'erreur à plus haut niveau : il
> s'agit de remonter l'erreur le plus précisément possible et de
> décider de la politique de gestion des erreurs (si tel traitement
> plante, qu'est-ce que je fais ?). Je ne vois pas la différence
> entre les codes d'erreur et les exceptions pour ça (à part que les
> exceptions sont des objets faciles à remonter et qui peuvent
> contenir facilement beaucoup d'information).

Euh... Comment dire... Non. Tu as au contraire moins
d'information parce qu'elle est moins fine. L'exception que tu
récupères tout en haut est une exception sur un ensemble de lignes de
code (sinon, tu utiliserais une gestion à la C). L'information sur ce
qui s'est passé réellement est difficile à extraire.



Je voulais dire que tu peux entasser facilement plein d'information
dans l'objet, c'est tout.
Mais le code d'erreur que tu récupères tout en haut, il ne concerne pas
un ensemble de lignes de code ?


>> la syntaxe java consiste à mettre des
>> gestionnaires d'exception un peu partout,
>
> Non.

Ah bon ? Les try{} catch() que mon compilo m'impose ne sont
pas obligatoires ?



S'il te l'impose, sans doute. Mais ce n'est pas la même chose que "un
peu partout". Il y en a besoin à certains endroits seulement. Il y a
beaucoup moins de chose à écrire que pour gérer des codes d'erreur et
tout libérer sur le trajet retour.


>> renvoyer l'exception au père,
>> grand'père ou arrière-grand'père voire pire par un throw.
>
> En quoi c'est pire ?

Parce que ça saute des appels de fonction. Si tu ne vois pas
la différence entre les deux façons de faire, je ne puis rien pour
toi.



Je vois très bien la différence, et ça saute les appels de fonction
parce qu'il n'y a rien à faire, ce n'est pas compliqué à comprendre
quand même...

En C tu es *obligé* de tout gérer pas à pas, de gérer les erreurs
*partout* parce que dans de très nombreuses fonctions tu as quelque
chose à libérer (ne serait-ce que de la mémoire). En Java tu n'as pas à
faire ça : tu te contentes de protéger les ressources qui doivent
l'être (beaucoup moins de choses qu'en C, ça ne concerne que quelques
types de ressources) et de traiter le problème à un second niveau (plus
haut) pour décider ce comment l'appli doit réagir à cet événement
imprévu.

Et je ne vois pas en quoi être obligé de tout se taper à la main c'est
moins pire que juste le faire là où il faut (remarque en C il faut
aussi le faire "juste là où il faut", sauf que c'est partout ; ah ben
non, même là où il n'y a rien à faire il faut se taper la remonté des
codes d'erreur quand même).


>> Le seul
>> moyen de gérer correctement une erreur est de la remonter le long
>> de la pile en la gérant à chaque appel de fonction.
>
> L'exception remonte effectivement la pile. Et il n'y a que quelques
> points où il y a réellement besoin de la traiter, contrairement au
> C. Donc au lieu d'étaler partout du code de gestion de la mémoire
> qui doit être gérée à la main partout (et qui *oblige* à une
> gestion pas à pas de l'erreur), on s'en dispense en Java et on ne
> gère les exceptions que dans le cas de la libération de certaines
> ressources (il y en a assez peu).

Et c'est exactement ce que je reproche aux exceptions.



De ne pas être obligé de se faire chier à écrire du code partout pour
traiter les erreurs et arriver au même résultat ? C'est vrai, c'est trop
triste...