tag:blogger.com,1999:blog-62004263390831463382024-03-13T12:13:55.586+01:00onof blogDiario di un programmatore e <a href="http://www.scala-lang.org/">SCALA</a>toreUnknownnoreply@blogger.comBlogger24125tag:blogger.com,1999:blog-6200426339083146338.post-20611713846070348942012-10-28T23:28:00.000+01:002012-10-28T23:33:27.678+01:00Android: fragments e UI designersUltimamente lavoro molto in Android, a contatto con UI designers molto bravi e meno bravi.<br />
<br />
Premetto che sono d'accordo con <a href="http://www.codinghorror.com/blog/2006/11/this-is-what-happens-when-you-let-developers-create-ui.html">questo celebre post di Jeff Atwood</a>. Però lasciando fare tutto ai designers si rischia l'opposto: se non conosce le opportunità offerte della tecnologia, il designer potrebbe fare assunzioni sbagliate sulla possibilità di certe soluzioni o semplicemente ignorarle. Inoltre sappiamo bene come sia facile in Italia improvvisarsi in qualsiasi ruolo, soprattutto quando va di moda.<br />
<br />
Ad esempio un designer sprovveduto potrebbe credere che un'applicazione Android dovrebbe essere uguale per tablet e smartphone, per risparmiare sullo sviluppo.<br />
E allora via con bellissimi bottoni immensi senza testo al centro! Lo store è pieno di applicazioni che per un tablet da 10 pollici diventano così:<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<br />
<div class="separator" style="clear: both; text-align: center;">
</div>
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfgf0m5J8S7C24MiNLwTxHW8nXIv1kZRvTE4ME1cR8j3dhJw_sP57NOmxSWo8O5Xfn4SYPhU2HOeqUKT0R_2n2ImnbmXc_vaxsQGxTCHZJF-6S6vhgMmyW_QEqxg0-nk2O6Poy1Vv83gPO/s1600/buttons.png" imageanchor="1" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="320" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgfgf0m5J8S7C24MiNLwTxHW8nXIv1kZRvTE4ME1cR8j3dhJw_sP57NOmxSWo8O5Xfn4SYPhU2HOeqUKT0R_2n2ImnbmXc_vaxsQGxTCHZJF-6S6vhgMmyW_QEqxg0-nk2O6Poy1Vv83gPO/s320/buttons.png" width="200" /></a></div>
Questo magari perché il designer non sapeva che in Android i <a href="http://developer.android.com/reference/android/app/Fragment.html">fragments</a> permettono di riutilizzare le logiche del programma in modo del tutto trasparente rispetto al layout scelto per il dispositivo e ha scartato la possibilità di mostrare, per i tablet, il contenuto direttamente nell'activity principale.<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-44032870464585153302012-05-29T13:58:00.000+02:002012-05-29T13:59:29.615+02:00Introduzione a Flag Driven DevelopmentCredo che ad ogni sviluppatore sia capitato di lavorare con questo approccio, dalle dinamiche molto interessanti. Generalmente un prodotto o una una logica in un software comincia con un algoritmo del tipo:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;">per ogni x tale che x appartiene all'insieme A<br />esegui l'operazione f(x)</span><br />
<br />
Inizialmente va tutto bene e tutti sono entusiasti del prodotto. Inevitabilmente qualcuno fa notare che così com'è non va bene, e bisognerebbe distinguere una situazione in cui l'operazione su x non va fatta. <br />
<br />
La soluzione a questo problema, secondo l'approccio Flag Driven Development è: aggiungere un flag su x. Il nostro algoritmo diventa:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;">per ogni x tale che x appartiene all'insieme A </span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> se x.flag = falso</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> esegui l'operazione f(x)</span><br />
<br />
Qualche volta il flag indica che bisogna eseguire un'altra funzione:<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;"><br /></span><br />
<span style="font-family: 'Courier New', Courier, monospace;">per ogni x tale che x appartiene all'insieme A </span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> se x.flag = falso</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> esegui l'operazione f(x)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> altrimenti</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">esegui l'operazione g(x)</span><br />
<br />
<br />
Come si vede, l'approccio è incrementale perché è sempre possibile aggiungere il flag del flag e rendere il sistema più potente:<br />
<br />
<br />
<span style="font-family: 'Courier New', Courier, monospace;">per ogni x tale che x appartiene all'insieme A </span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> se x.flag1 = falso</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> se x.flag2 = falso</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> esegui l'operazione f(x)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> altrimenti</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">esegui l'operazione h(x)</span><br />
<span style="font-family: 'Courier New', Courier, monospace;"> altrimenti</span><br />
<table cellpadding="0" cellspacing="0" class="tr-caption-container" style="float: right; margin-left: 1em; text-align: right;"><tbody>
<tr><td style="text-align: center;"><a href="http://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_the_Napoleonic_Kingdom_of_Italy.svg/600px-Flag_of_the_Napoleonic_Kingdom_of_Italy.svg.png" imageanchor="1" style="clear: right; margin-bottom: 1em; margin-left: auto; margin-right: auto;"><img border="0" height="133" src="http://upload.wikimedia.org/wikipedia/commons/thumb/b/bc/Flag_of_the_Napoleonic_Kingdom_of_Italy.svg/600px-Flag_of_the_Napoleonic_Kingdom_of_Italy.svg.png" width="200" /></a></td></tr>
<tr><td class="tr-caption" style="text-align: center;"><span style="font-size: small;">Bandiera del Regno d'Italia Napoleonico</span></td></tr>
</tbody></table>
<span style="font-family: 'Courier New', Courier, monospace;"> </span><span style="font-family: 'Courier New', Courier, monospace;">esegui l'operazione g(x)</span><br />
<span style="font-family: 'Courier New', Courier, monospace; font-size: x-small;"><br /></span><br />
Si può evitare il flag? Sì, ma perché dovremmo? Questo approccio è un obbrobrio? Anche secondo me, ciò non toglie che è sempre molto usato.<br />
Nei prossimi post forse ritornerò sull'argomento per esplicitare meglio certe dinamiche o forse no.<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-60322116102503888032011-11-05T12:42:00.000+01:002011-11-05T12:42:05.666+01:00Machine Learning e Scala al JugMarche 2<p>Pubblico le slide del meeting:<br />
</p><div style="width:425px" id="__ss_9949056"><strong style="display:block;margin:12px 0 4px"><a href="http://www.slideshare.net/onof80/jugmarche-machine-learning-usi-pratici-di-supervised-learning" title="JugMarche: Machine learning: usi pratici di supervised learning" target="_blank">JugMarche: Machine learning: usi pratici di supervised learning</a></strong> <iframe src="http://www.slideshare.net/slideshow/embed_code/9949056" width="425" height="355" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe> <div style="padding:5px 0 12px">View more <a href="http://www.slideshare.net/" target="_blank">presentations</a> from <a href="http://www.slideshare.net/onof80" target="_blank">Onofrio Panzarino</a> </div></div><p>... e ringrazio tutti i partecipanti. Il codice delle demo sarà ufficialmente pubblicato su github ASAP :)</p><br />
<p>Stay tuned!</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-64680872990265921782011-10-15T16:47:00.000+02:002011-10-15T16:47:13.387+02:00Machine Learning e Scala al JUG MarcheSabato 29 ottobre terrò un talk di un'ora circa al Jug Marche a Falconara Marittima (AN) trattando di usi pratici di Machine Learning ed esempi in Scala. Maggiori dettagli sull'evento ed iscrizione(gratuita) <a href="http://jugmarche.posterous.com/meeting-di-ottobre">qui</a>.<br />
<br />Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-50182476942522614502011-09-09T20:53:00.002+02:002011-09-09T20:53:36.849+02:00Scala-recog accettato da scala-tools<div class='posterous_autopost'><p>Per me la buona notizia della settimana è che <a href="http://code.google.com/p/scala-recog/" title="scala-recog">scala-recog</a> è stato accettato da <a href="http://scala-tools.org/" title="scala-tools">scala-tools</a> quindi sarà scaricabile e importabile nei progetti scala con sbt, dallo stesso repository che contiene nientepopodimeno che scalaz, scalala, Lift, etc. etc.</p></div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-80479923513700693452011-08-06T12:42:00.001+02:002011-08-06T19:49:50.475+02:00scala-recog: flessibilità con logistic regression<p>In <a href="http://code.google.com/p/scala-recog/wiki/LogisticRegressionTraits">questa wiki page</a> ho messo qualche esempio sulla flessibilità che si può raggiungere usando le stackable modification.</p>
<p>In realtà con la logistic regression con scala-recog era per ottenere più flessibilità senza rinunciare alle ottimizzazioni necessarie per un algoritmo di training.</p>
<p>Ma quel che vorrei raggiungere raggiunge uno sforzo estra di desgin. Mi piacerebbe una libreria molto generale, indipendente dal dominio di applicazione.</p>
<p>Per esempio mi piacerebbe poter scrivere qualcosa tipo:</p>
<pre class="brush: scala">
import org.scalarecog.logisticregression.SigmoidClassifier._
val myStuff = List(
Stuff(3, 2.1, "just"),
Stuff(2, 1.1, "an"),
Stuff(3, 1.2, "example")
)
val trainingSet = myStuff toTrainingSet (
_.number, _.number2), _.classLabel
)
val classifier = trainingSet.train
</pre>
<p>Ma mi piacerebbe anche raggiungere questo tipo di flessibilità:</p> <pre class="brush: scala">
val classifier = (
for(stuff <- trainingSet; writer <- stuff.toWriter )
) train
(classifier.log) foreach(println(_))
</pre>
<p>Forse si può prevedendo un supporto per le monadi nei training set. Un esempio di monade può essere <a href="http://blog.tmorris.net/the-writer-monad-using-scala-example/">questo di Tony Morris</a>.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-46173857904214861082011-07-29T13:12:00.001+02:002011-07-29T13:33:03.576+02:00Alberi di decisione con scala-recog<a href="http://code.google.com/p/scala-recog/">scala-recog</a> è un progetto open-source che ho creato su Google Code, una libreria di algoritmi di machine learning totalmente scritta in Scala.
Uno di questi è ID3, un algoritmo che permette di costruire un albero di decisione basandosi su un training set di elementi già classificati.
<h2>Esempio: classificare curricula</h2>
Supponiamo di avere un sito per la ricerca di lavoro e vogliamo classificare i curricula inseriti per mostrarli agli utenti che cercano delle determinate figure.
Dai curricula si possono estrarre una enomre quantità di dati ma supponiamo di voler estrarre solo questi:
<ul>
<li>se il candidato ha delle certificazioni</li>
<li>se è una persona loquace</li>
<li>se è iscritto al golf club</li>
<li>se ha una laurea o un master</li>
</ul>
e mettiamo tutto in una classe:
<pre class="brush: scala">
case class Person(
val hasCertifications : Boolean,
val isTalkative : Boolean,
val golfClub : Boolean,
val hasMasterDegree : Boolean,
val job : String
)
val persons = Person(hasCertifications = true, isTalkative = false,
golfClub = false, hasMasterDegree = true,
job = "Programmer") ::
Person(hasCertifications = false, isTalkative = false,
golfClub = false, hasMasterDegree = true,
job = "Junior Programmer") ::
Person(hasCertifications = true, isTalkative = false,
golfClub = false, hasMasterDegree = false,
job = "Programmer") ::
Person(hasCertifications = false, isTalkative = true,
golfClub = false, hasMasterDegree = true,
job = "Seller") ::
Person(hasCertifications = false, isTalkative = true,
golfClub = false, hasMasterDegree = false,
job = "Seller") ::
Person(hasCertifications = true, isTalkative = true,
golfClub = false, hasMasterDegree = false,
job = "Seller") ::
Person(hasCertifications = false, isTalkative = true,
golfClub = true, hasMasterDegree = true,
job = "CEO") ::
Person(hasCertifications = false, isTalkative = false,
golfClub = true, hasMasterDegree = false,
job = "CEO") ::
Person(hasCertifications = false, isTalkative = false,
golfClub = true, hasMasterDegree = false,
job = "CEO") ::
Nil
</pre>
Nella lista <em>persons</em> ho messo il mio training set. Per usare l'algoritmo ID3, basta importare l'oggetto giusto e usare la lista come training set:
<pre class="brush: scala">
import org.scalarecog.decisiontree._
def toVector(p : Person) = Vector(p.hasCertifications, p.isTalkative, p.golfClub, p.hasMasterDegree)
val dataset = persons map (p => (toVector(p), p.job))
val tree = new ID3[Boolean,String] buildTree dataset
</pre>
La funzione <em>toVector</em> server perché la classe ID3 ha bisogno di un
<a href="http://www.scala-lang.org/api/current/scala/collection/immutable/Vector.html">Vector</a>.<br/>
Ora <em>tree</em> può classificare una nuova persona:
<pre class="brush: scala">
val newPerson = Person(false, false, false, false, "?")
assert(
tree.classify(toVector(newPerson)) == "Junior Programmer"
)
</pre>
Ma sarebbe carino visualizzare l'albero di decisione creato da ID3.
Con <a href="http://www.jgraph.com/jgraph.html">JGraph</a> è semplicissimo e otteniamo questo:
<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjaT0dqd_1pG6zTjUlu0iNVJzHBLl9RsOCmdoHZYqZ1ipaU4WL652Qw0_DiL0l547FEBiUXa73JAqbto7HPivKC3wWD0t8NAvSyJr2PLlHrN3WiGDl4OIPhzOwnEcq3Vk3FgPGrnGPozrf/s1600/scalarecog.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="400" width="293" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgjaT0dqd_1pG6zTjUlu0iNVJzHBLl9RsOCmdoHZYqZ1ipaU4WL652Qw0_DiL0l547FEBiUXa73JAqbto7HPivKC3wWD0t8NAvSyJr2PLlHrN3WiGDl4OIPhzOwnEcq3Vk3FgPGrnGPozrf/s400/scalarecog.jpg" /></a></div>
Ehi! È proprio l'algoritmo usato nella vita reale! ^_^ <br/>
Ecco qui il codice completo:
<pre class="brush: scala">
package scalarecoggraph
import org.scalarecog.decisiontree._
import javax.swing.JFrame
import com.mxgraph.swing.mxGraphComponent
import com.mxgraph.view.mxGraph
class Program(tree : DecisionTree[Vector[Boolean], String], propertyNames : Vector[String]) extends JFrame("ScalaRecog") {
type Tree = DecisionTree[Vector[Boolean], String]
type Vertex = (AnyRef, (Double, Double))
draw()
def draw() {
val graph: mxGraph = new mxGraph
val root = graph.getDefaultParent
def draw(t : Tree, parentPos : (Double, Double), offset : (Int, Int)) : Vertex = {
def createVertex(label : String, action : Vertex => Unit = v => {}) : Vertex = {
val vertexSize = (100, 30)
val newPos = (parentPos._1 + offset._1, parentPos._2 + offset._2)
val created = (graph.insertVertex(root, null, label, newPos._1, newPos._2 , vertexSize._1, vertexSize._2), newPos)
action(created)
created
}
def createEdge(label : String, from : Vertex, to : Vertex) = graph.insertEdge(root, null, label, from._1, to._1)
t match {
case a : DecisionLeaf[Vector[Boolean],String] => createVertex(a.label)
case a : DecisionBranchVector[String,Boolean] =>
createVertex(propertyNames(a.index), n => {
for ( ((label, child), index) <- a.branches.zipWithIndex )
createEdge(label.toString, n, draw(child, n._2, (120*index, offset._2)))
})
}
}
graph.getModel.beginUpdate
try {
draw(tree, (0, 0), (120, 120))
}
finally {
graph.getModel.endUpdate
}
getContentPane.add(new mxGraphComponent(graph))
}
}
object Program {
case class Person(
val hasCertifications : Boolean,
val isTalkative : Boolean,
val golfClub : Boolean,
val hasMasterDegree : Boolean,
val job : String
)
def main(args : Array[String]) : Unit = {
val persons = Person(hasCertifications = true, isTalkative = false, golfClub = false, hasMasterDegree = true, job = "Programmer") ::
Person(hasCertifications = false, isTalkative = false, golfClub = false, hasMasterDegree = true, job = "Junior Programmer") ::
Person(hasCertifications = true, isTalkative = false, golfClub = false, hasMasterDegree = false, job = "Programmer") ::
Person(hasCertifications = false, isTalkative = true, golfClub = false, hasMasterDegree = true, job = "Seller") ::
Person(hasCertifications = false, isTalkative = true, golfClub = false, hasMasterDegree = false, job = "Seller") ::
Person(hasCertifications = true, isTalkative = true, golfClub = false, hasMasterDegree = false, job = "Seller") ::
Person(hasCertifications = false, isTalkative = true, golfClub = true, hasMasterDegree = true, job = "CEO") ::
Person(hasCertifications = false, isTalkative = false, golfClub = true, hasMasterDegree = false, job = "CEO") ::
Person(hasCertifications = false, isTalkative = false, golfClub = true, hasMasterDegree = false, job = "CEO") ::
Nil
def toVector(p : Person) = Vector(p.hasCertifications, p.isTalkative, p.golfClub, p.hasMasterDegree)
val dataset = persons map (p => (toVector(p), p.job))
val tree = new ID3[Boolean,String] buildTree dataset
val newPerson = Person(false, false, false, false, "?")
assert(
tree.classify(toVector(newPerson)) == "Junior Programmer"
)
val frame = new Program(tree, Vector("Has certifications?", "Is talkative?", "Likes playing golf?", "Has a master degree?"))
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE)
frame.setSize(400, 320)
frame.setVisible(true)
}
}
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-54801638320576154412011-07-17T22:11:00.000+02:002011-07-17T22:11:52.866+02:00algoritmo k-NN: meglio in ScalaStavo leggendo <a href="http://www.manning.com/pharrington/">questo libro su machine learning</a>. È un buon libro ma mi ero stufato della verbosità di Python, con cui sono presentati gli algoritmi, quindi ho scritto un'implementazione dell'<a href="http://en.wikipedia.org/wiki/K-nearest_neighbor_algorithm">algoritmo k-NN</a> in Scala:
<pre class="brush: scala">
package knn
class Knn[TData, TClass,
TDistance <% Ordered[TDistance] ]
(
val k : Int,
val dataset : List[TData],
val getClassOfData : TData => TClass,
val getDistance : (TData, TData) => TDistance
)
{
if(k < 1)
throw new scala.IllegalArgumentException("k must be positive")
def classify(data : TData) : TClass = {
// Compute distances between tested data and dataset items
val distances = for( d <- dataset ) yield (d, getDistance(d, data))
// sort data by distance
val sorted = distances sortBy ( d => d._2 )
// take first k items
val firstk = sorted take k
// group by labels
val classes = firstk groupBy (d => getClassOfData(d._1))
// get most frequent label
val classification = classes maxBy (g => g._2.length)
classification._1
}
}
</pre>
Wow, ho scritto questa classe in dieci minuti funziona con ogni tipo di dataset dove sia definita una distanza e ovviamente una classificazione, come si può vedere con questo test (scritto con <a href="http://www.scalatest.org/">ScalaTest</a>):
<pre class="brush: scala">
package knn
import org.scalatest._
import org.scalatest.matchers._
import scala.math._
class KnnTest extends FlatSpec with ShouldMatchers {
"2nn" should " classify correctly with a sample near two well-known labelled items" in {
val alg = new Knn(2,
List((3, "ok"), (18, "ok"), (21, "high"), (64, "high")),
(i : (Int, String)) => i._2,
(i1: (Int, String), i2: (Int, String)) => abs(i1._1 - i2._1))
val classified = alg.classify((4, ""))
classified should equal ("ok")
}
}
</pre>
Naturalmente il codice può essere ottimizzato e generalizzato ma mostra come si possa scrivere codice veramente disaccoppiato e generale in Scala.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-27169497049457083072011-07-14T13:57:00.001+02:002011-07-14T13:59:15.827+02:00Aboliamo static<p>Su <a href="http://twitter.com/#!/onof80/statuses/90740628048183296">twitter ho proposto scherzosamente</a> di abolire la parola chiave <q>static</q> dei linguaggi garbage collected.
All'inizio era appunto uno scherzo, poi mi sono detto:
<blockquote>posso effettivamente fare a meno di <em>static?</em></blockquote>
Innanzitutto, perché fare a meno di static? Perché può dare un sacco di problemi.
</p>
<h2>Factory</h2>
<p>
Prendiamo una classe e un'innocente metodo static per costruirla:
<pre class="brush: java">
public class DumbClass {
private String foo;
public String getFoo() { return foo; }
public void setFoo(String foo) { this.foo = foo; }
private String initializedStuff;
public String getInitializedStuff() { return initializedStuff; }
private DumbClass(String foo, String initializedStuff) {
this.initializedStuff = initializedStuff;
this.foo = foo;
}
public static DumbClass create(Context c) {
return new DumbClass( c.doSomethingToGetFoo(), c.doSomethingToGetStuff() );
}
}
</pre>
Inevitabilmente, come dice Alan Shalloway, <a href="http://prasanthaboutjava.blogspot.com/2008/06/design-patterns-explained-by-alan.html">le specifiche cambiano</a> e uno dei vostri clienti vuole che, solo per lui, <em>foo</em> sia in CamelCase piuttosto che tutto MAIUSCOLO. E voi:
<blockquote>Facile: mettiamo in una libreria (che diamo solo a lui) una classe che estend.. Ops: non si può estendere, è un metodo statico! E se invece avessi fatto un'abstract factory?</blockquote>
<pre class="brush: java">
public class DumbClass {
private String foo;
public String getFoo() { return foo; }
public void setFoo(String foo) { this.foo = foo; }
private String initializedStuff;
public String getInitializedStuff() { return initializedStuff; }
DumbClass(String foo, String initializedStuff) {
this.initializedStuff = initializedStuff;
this.foo = foo;
}
}
public interface IDumbClassFactory {
DumbClass create(Context c);
}
public class DefaultDumbClassFactory {
public DumbClass create(Context c) {
return new DumbClass( c.doSomethingToGetFoo(), c.doSomethingToGetStuff() );
}
}
</pre>
Allora basterebbe wrappare <em>DefaultDumbClassFactory</em> o fare un'altra implementazione di <em>IDumbClassFactory</em> e avrei fatto! <br />
<blockquote>Morale: <strong>non usare metodi statici, meno che mai pubblici!</strong></blockquote>
</p>
<h2>Campi privati</h2>
<p>
A volte capita di voler tenersi un contatore di istanze di una certa classe per sapere quante ce ne sono in giro. E si fa con un bel campo static:
<pre class="brush: java">
public class Foo {
private static int howMany;
public Foo(Something s) {
howMany++;
}
...
}
</pre>
Risultato? Scoprite che in realtà quel contatore non lo legge mai nessuno, anzi, se usate la libreria su un web server che gira per 2 anni di fila, alla fine vi va in overflow e causa un eccezione che ovviamente non gestite perché non ci avevate pensato. Oppure vorrete che non tenga traccia delle classi figlie, oppure per qualcuna sì e qualcuna no, e allora? Scoprite che vi serviva un'abstract factory.
<blockquote>Morale: quando sto per scrivere <em>static</em> <strong>ci penso due volte e quasi sempre alla fine scrivo: <em>interface</em></strong></blockquote>
</p>
<p style="text-align: left;">
<a title='By Photo: Andreas Praefcke (Self-published work by AndreasPraefcke) [CC-BY-3.0 (www.creativecommons.org/licenses/by/3.0) or GFDL (www.gnu.org/copyleft/fdl.html)], via Wikimedia Commons' href='http://commons.wikimedia.org/wiki/File:Wolfsburg_VW-Werk.jpg'><img width='400' alt='Wolfsburg VW-Werk' src='http://upload.wikimedia.org/wikipedia/commons/thumb/7/71/Wolfsburg_VW-Werk.jpg/800px-Wolfsburg_VW-Werk.jpg'/></a>
</p>Unknownnoreply@blogger.com1tag:blogger.com,1999:blog-6200426339083146338.post-10675530165459462682011-07-13T19:22:00.006+02:002011-07-14T13:04:12.691+02:00Secondo articolo su ScalaNel mio <a href="http://www2.mokabyte.it/cms/p/mb164/scala-2">secondo articolo introduttivo su Scala</a> affronto una questione secondo me cruciale per Scala, ossia la sue grandi potenzialità nella manipolazione di collezioni.
<p>Segnalo anche il <a href="http://www2.mokabyte.it/cms/p/mb164/bettersoftware2011">bel resoconto del Better Software 2011</a> di Francesco Saliola, interessante e tanto più utile per chi come me non ha potuto partecipare.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-87078881933602842132011-06-29T13:27:00.001+02:002011-07-14T13:07:00.218+02:00Serie di articoli d'introduzione a Scala, in italianoPrimo articolo di una serie d'introduzione a Scala, in italiano, sulla rivista online <a href="http://www.mokabyte.it/">MokaByte</a>:
<div style="padding: 20px;">
<a href="http://www2.mokabyte.it/cms/p/mb163/scala-1">Introduzione a Scala - Prima parte: i perché di un linguaggio</a>
</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-22060881765573702862011-06-21T21:20:00.002+02:002011-06-22T22:51:17.064+02:00Option è un container (e una monade)!Supponiamo di avere una lista di Option:
<pre class="brush: scala">
val myList = List(
Some(1),
Some(4),
None,
Some(5)
)
</pre>
e volete solo i valori, quindi <span class="code">List(1, 4, 5)</span>. Qualche volta trovate codice analogo al seguente, magari scritto da me l'anno scorso :)
<pre class="brush: scala">
val values = myList filter (! _.isEmpty) map (_.get)
assert( values == List(1, 4, 5) )
</pre>
<b>Orribile!</b><br />
Infatti, essendo <span class="code">Option</span> un container possiamo (e dobbiamo) fare questo:
<pre class="brush: scala">
val values = myList.flatten
assert( values == List(1, 4, 5) )
</pre>
o, al massimo:
<pre class="brush: scala">
val values = for(
Some(a) <- myList
) yield a
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-3739001997850099422011-05-06T13:52:00.001+02:002011-05-06T13:55:47.460+02:00È uscito il mio <a href="http://www2.mokabyte.it/cms/p/mb162/nosql-3">terzo e ultimo articolo sui database <acronym title="Not Only SQL">NoSQL</acronym></a> sulla rivista <a href="http://www.mokabyte.it">MokaByte</a>; questa volta si parla di <a href="http://neo4j.org/">neo4j</a>.
<div class="separator" style="clear: both; text-align: left;">
<a href="http://www2.mokabyte.it/cms/p/mb162/nosql-3" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" width="320" src="http://www2.mokabyte.it/cms/figureproviderservlet?figureId=YHX-N3M-OZF_7f000001_32318148_b28b257b--fig01.jpg" /></a></div>
Gli altri due articoli erano: <a href="http://www2.mokabyte.it/cms/p/mb160/nosql-1">uno introduttivo sui database NoSQL</a> e <a href="http://www2.mokabyte.it/cms/p/mb161/nosql-2">uno su MongoDB</a>.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-37640206560509583832011-04-28T13:50:00.002+02:002011-04-28T14:11:32.852+02:00Da Scala a LINQSpesso, durante il mio lavoro diurno (C# e Javascript) mi trovo a rimpiangere gli strumenti di cui dispongo nel mio lavoro notturno (Scala e Java).
<p>
Stavolta è andata così. Mi trovavo spesso a scrivere codice non transazionale in cui devo fare un'operazione su una serie di oggetti ma le eccezioni dovevano essere gestite ed aggregate, in questo modo:
<pre class="brush: csharp">
var erroriGestiti = new List<QualcheCosa>();
foreach( var item in items ) {
try {
FaiQualcosaCon(item);
}
catch( QualcheTipoDiEccezione excp) {
a.Add( CreaQualcheCosaDa(excp) );
}
}
return erroriGestiti;
</pre>
<a style="float: right;" title='By User:Mattes (Own work) [Public domain], via Wikimedia Commons' href='http://commons.wikimedia.org/wiki/File:Vigili_del_Fuoco_(Vatican)_-_fleet.jpg'><img width='400' alt='Vigili del Fuoco (Vatican) - fleet' src='http://upload.wikimedia.org/wikipedia/commons/thumb/5/5f/Vigili_del_Fuoco_%28Vatican%29_-_fleet.jpg/500px-Vigili_del_Fuoco_%28Vatican%29_-_fleet.jpg'/></a>
Ed ero ovviamente stufo di ripetere questo costrutto. Ora, in Scala astrarre il concetto "collezionare le eccezioni di operazioni in sequenza" è un gioco da ragazzi, per cui lo tralascio. Però, anche se dire che LINQ ti permette di fingere di essere in Scala sarebbe un'assurdità (neanche F# te lo fa dire), può darti una mano:
<pre class="brush: csharp">
public static
IEnumerable<TReturn> CollectErrors<TItem, TException, TReturn>(
this IEnumerable<TItem> items,
Action<TItem> act,
Converter<TException, TReturn> exceptionHandler
)
where TException : Exception
{
if (items == null)
throw new ArgumentNullException("items");
if (act == null)
throw new ArgumentNullException("act");
if (exceptionHandler == null)
throw new ArgumentNullException("exceptionHandler");
return items
.Aggregate(new List<TReturn>(),
(collector, item) =>
{
try
{
act(item);
}
catch (TException ex)
{
collector.Add(exceptionHandler(ex));
}
return collector;
});
}
// e questo mi permette di scrivere:
[TestMethod]
public void TestMethod1()
{
var expected = new[] { "error", "error", "error" };
var actual = new[] { 1, 2, 3, 4, 5, 6 }
.CollectErrors(i => { if (i > 3)
throw new IndexOutOfRangeException();
},
(IndexOutOfRangeException e) => "error");
Assert.IsTrue(actual.SequenceEqual(expected));
}
</pre>
certo non è una sintassi molto chiara come potrebbe essere in Scala, ma non è poi tanto male, no?
</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-18707468270518408552011-04-13T13:56:00.003+02:002011-04-13T14:18:14.335+02:00Scala e MongoDB<p>Dal sito ufficiale di <a href="http://www.mongodb.org/">MongoDB</a> si apprende che <a href="https://github.com/mongodb/casbah">Casbah</a> <a href="http://www.mongodb.org/display/DOCS/Java+Language+Center">è il driver ufficiale per Scala per MongoDB</a>. Queste API sono molto di basso livello, in quanto wrappano il driver JAVA per MongoDB. Ad esempio, per creare un utente nella nostra collection per MongoDB dobbiamo scrivere una cosa del genere:</p>
<pre class="brush: scala">
val onof80 = MongoDBObject("userName" -> "onof80",
"openId" -> "http://.....",
"age" -> 31,
"interests" -> "Java,Scala")
</pre>
che si mappa in un oggetto JSON simile a questo:
<pre class="brush: javascript">
{
userName : "onof80",
openId : "http://.....",
age : 31,
interests: "Java,Scala"
}
</pre>
Interessante, ma sono abituato a <a href="https://github.com/osinka/mongo-scala-driver">mongo-scala-driver</a>, che mi permette di definire una classe per l'oggetto User:
<pre class="brush: scala">
class User(
userName : String,
openId : String,
age : Option[Int],
interests : String
) extends MongoObject {
override def toString: String = userName
}
</pre>
e quindi, al prezzo di un companion object che ometto, di riutilizzarlo:
<pre class="brush: scala">
val onof80 = new User("onof80", "http://.....", 31, "Java,Scala");
(dbCollection of User) += onof80;
</pre>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-83307622848493792982011-04-01T23:45:00.002+02:002011-04-02T00:07:01.423+02:00Monad state con scalazDa un po' di tempo studio <a href="http://code.google.com/p/scalaz/">scalaz</a>. Una delle strutture dati più interessanti è <em>State</em>. Permette di mantenere lo stato degli oggetti tra le transizioni, ed è molto utile quando si vogliono concatenare delle operazioni in modo puramente funzionale, senza riassegnare le variabili. <br />
Ad esempio, immaginiamo di avere un messaggio, con l'elenco dei destinatari a cui è stato inviato:
<pre class="brush: scala">
import java.util.Date
case class Message(
text : String,
sent : List[(String, Date)] = Nil
){
def sendTo(address : String) : Message =
Message(text, (address, new Date) :: sent)
override def toString = "Message " + text +
sent.map(s => s._1 + " on " + s._2)
.mkString(" sent to ", ", to ", "")
}
</pre>
Ora, se volessimo estendere la funzione <em>sendTo</em> in modo da prendere una lista di destinatari a cui inviare il messaggio, con <em>State</em> possiamo fare così:
<pre class="brush: scala">
import scalaz._
import Scalaz._
def sendTo(addresses : List[String])
: State[Message, List[(String, Message)]] =
addresses match {
case head :: tail =>
for( s <- init[Message];
n <- modify[Message]( _ sendTo head ) ;
t <- sendTo(tail)
) yield (head, s sendTo head) :: t
case Nil => state(i => (i, Nil))
}
</pre>
Questa funzione prende in input la lista di destinatari e ritorna un oggetto che permette di effettuare l'operazione di inviare un messaggio a quei destinatari, ad esempio:
<pre class="brush: scala">
println(
sendTo(List("Onofrio", "Claudia"))
(Message("Hello World!"))
)
</pre>
che restituisce una tupla contenente il messaggio finale più la lista di tutti i passaggi di stato:
<pre style="font-size: small; color: green;">
(Message Hello World!
sent to Claudia on Fri Apr 01 23:21:49 CEST 2011,
to Onofrio on Fri Apr 01 23:21:49 CEST 2011,
List((Onofrio, Message Hello World!
sent to Onofrio on Fri Apr 01 23:21:49 CEST 2011),
(Claudia, Message Hello World!
sent to Claudia on Fri Apr 01 23:21:49 CEST 2011,
to Onofrio on Fri Apr 01 23:21:49 CEST 2011)))
</pre>
Ovviamente, il metodo è deve essere privo di side-effect, altrimenti, poiché viene eseguite più volte gli effetti sono imprevedibili. Per ottenere come side-effect l'invio di una e-mail, per esempio, da quanto ho capito è necessaria la monad <em>Writer</em>. Scriverò un post appena sarò riuscito a farlo con scalaz.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-8898902725046472732011-03-28T18:11:00.025+02:002011-04-02T00:09:02.547+02:00Teorema CAP: disponibilitàRiguardo al <a href="http://www2.mokabyte.it/cms/article.run?permalink=mb160_nosql-1">mio articolo su MokaByte</a>, ho avuto uno scambio di e-mail con alcuni lettori riguardo il teorema CAP, in particolare sulla disponibilità del sistema. Il primo è stato <b>Enrico Oliosi</b> che mi ha chiesto:
<blockquote>Se desidero mantenere la consistenza di dati su tutti i nodi e voglio che il sistema sia tollerante ai guasti, in che modo posso perdere la disponibilità del sistema? Questa perdita si riferisce all'interno sistema o ad un singolo nodo?</blockquote>
Premettendo che non sono un ricercatore né un progettista di database NoSql (anzi, se a qualcuno di loro capitasse di leggere, lo invito a commentare eventuali inesattezze o madornali errori) provo a rispondere in base a quello che ho letto sull'argomento. La domanda, mi pare possa essere riassunta in: <blockquote>Cosa significa che il sistema non è disponibile? Cos'è un sistema non disponibile ma tollerante?</blockquote>
<a title='By Computer History Museum (archive.computerhistory.org) [CC-BY-3.0 (www.creativecommons.org/licenses/by/3.0)], via Wikimedia Commons' href='http://commons.wikimedia.org/wiki/File:Dec_pdp-6.lg.jpg'><img width='500' alt='Dec pdp-6.lg' src='http://upload.wikimedia.org/wikipedia/commons/3/31/Dec_pdp-6.lg.jpg'/></a>
Tempo fa ho letto un <a href="http://dbmsmusings.blogspot.com/2010/04/problems-with-cap-and-yahoos-little.html">post molto interessante di Daniel Abadi</a>, che secondo me può essere molto d'aiuto per rispondere. Se, calando il teorema CAP in pratica, per disponibilità si intende la possibilità di trovare una replica dei dati in caso di fallimento, cosa succede dunque ai sistemi <b>AP</b>, <b>CP</b> e <b>CA</b> in caso di network partition? Abadi dice: in realtà <i>sembrerebbe</i> che non ho tre alternative, <b>ma solo due: AP oppure CP/CA</b>, ossia consistenza oppure no, perché se voglio la consistenza: <ul><li>o non sono tollerante al partizionamento (il sistema non scambia messaggi, quindi in pratica non funziona)</li><li>oppure non è disponibile (quindi in pratica non funziona).</li></ul> Abadi vede in questo un'incompletezza del teorema CAP, dice che, per essere utile, un teorema a riguardo dovrebbe considerare anche la latenza del sistema e si dovrebbe suddividere l'analisi in due parti: in caso di funzionamento normale e in caso di partizionamento della rete, perché in effetti queste proprietà si esplicano in un certo istante nel tempo.
<br />
Secondo me, il punto è che, al di là di dispute accademiche, i vari sistemi Sql o NoSql, non rinunciano del tutto a una delle tre proprietà, ma di fatto ne rilassano una o più di una per raggiungere determinati scopi e in determinati tempi. Tant'è che Abadi porta ad esempio <a href="http://research.yahoo.com/node/2304">PNUTS</a> che sembra garantire una sola proprietà. In realtà, rilassa sia C e A in favore di una più bassa latenza. Ecco perché spesso è difficile catalogare un sistema secondo la nomenclatura CAP. Quello che si può fare è dare un'indicazione di massima. Tutto ciò perché CAP stabilisce quello che non può succedere in un istante, non quello che succede in generale.
Detto ciò, in cosa si traduce la perdita di disponibilità? In un fallimento dell'intero sistema o del singolo nodo? Se la disponibilità è la possibilità del sistema di supplire al fallimento di un nodo, quindi disponibilità rilassata significa che al fallimento di un nodo il sistema non riesce ad andare avanti come se niente fosse, ma il come dipende da come è stato progettato il sistema.
<br />
Provo, ad esempio ad ipotizzare come i tre sistemi potrebbero comportarsi in caso di partizionamento, a causa della rottura di un nodo:
<ul>
<li>
CA: i dati rimangono consistenti, il nodo rotto è stato sostituito da una replica che ha dati consistenti, ma alcune funzioni sono state disabilitate come la scrittura. Classica situazione <b>RDBMS</b>.
</li><li>
AP: perdita di consistenza, le due sottoreti continuano a funzionare (essere disponibili) in autonomia, il nodo rotto è stato sostituito da una replica in una delle sottoreti, ma i dati tra le reti divergono oppure i dati tra le reti non divergono ma la replica non ha dati consistenti con il nodo rotto (si sono persi gli ultimi n update). Quando la rete si metterà a posto, la consistenza (forse) si raggiungerà a regime (tipica situazione <b>NoSql</b>).
</li><li>
CP: le due sottoreti continuano a funzionare autonomamente (P) e ad avere dati tra loro consistenti (C) perché c'è un failover che ri-assembla la rete in un altro modo, ma poiché la disponibilità non è garantita, ci potrebbe essere un transitorio in cui il sistema non è per nulla raggiungibile, oppure che ci saranno diversi operazioni fallite (altra situazione <b>NoSql</b>).
</li></ul>
Ma il partizionamento potrebbe essere dato anche da altri fattori, o in altre modalità e il comportamento potrebbe non essere quello, perché magari i nodi non hanno tutti la stessa importanza o le stesse funzioni. Dipende da come è stato architettato il sistema.Unknownnoreply@blogger.com4tag:blogger.com,1999:blog-6200426339083146338.post-63250249958336808202011-03-08T19:12:00.009+01:002011-04-02T00:11:49.294+02:00Vi presento GridGain<div itemscope itemtype="http://data-vocabulary.org/Review">
<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.gridgain.com/" imageanchor="1" style="clear:left; float:left;margin-right:1em; margin-bottom:1em"><img border="0" height="31" width="111" src="http://www.gridgain.com/images/logo2_111x31.png" /></a></div>
Come <a href="http://onof80.blogspot.com/2011/03/codemotion-2011.html">promesso</a>, vi presento <a itemprop="itemreviewed" href="http://www.gridgain.com">GridGain</a>. <span itemprop="summary">Si tratta di un framework per permettervi di fare programmazione distribuita in modo molto semplice.</span> <span itemprop="description">Ciò che lo rende veramente potente è il supporto per Scala, infatti Scala dà il meglio di sé proprio in questi contesti. Supponete di avere una rete con <span itemprop="rating">5</span> nodi e la vostra applicazione suddivide un certo carico di un lavoro su tutti i nodi. Se il sistema scala orizzontalmente e passiamo a 50 nodi, dobbiamo rivedere tutto il programma? Non se usate GridGain.
Se inoltre siete stati bravi, e avete applicato i bei paradigmi funzionali alla vostra applicazione, il vostro codice è già scalabile.</span>
<br />
Ad esempio, avete una funzione in Scala per calcolare la <a href="http://it.wikipedia.org/wiki/E_(costante_matematica)">costante di Nepero</a>:
<pre class="brush: scala">
object Program {
def invFact(i : Int) : BigDecimal = i match {
case 0 => BigDecimal(1)
case n if n > 0 => (BigDecimal(1) / BigDecimal(n)) * invFact(n - 1)
}
def neper(iterations : Int) = {
(BigDecimal(0) /: ((1 to iterations) map invFact))( _ + _)
}
...
}
</pre>
Dove avete utilizzato la formula: <div class="separator" style="clear: both; text-align: center;">
<a href="http://upload.wikimedia.org/math/9/f/d/9fd1faf162499a102e7ca59ef1ed7e9f.png" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="50" width="363" src="http://upload.wikimedia.org/math/9/f/d/9fd1faf162499a102e7ca59ef1ed7e9f.png" /></a></div>
All'aumentare di <i>iterations</i> aumenta la precisione. È ovvio che può essere molto migliorato, è solo un esempio. Supponiamo adesso che volete farlo andare in parallelo. Con GridGain è semplicissimo:
<ol>
<li>accedete i vostri nodi (quanti ne volete/potete) lanciando <i>ggstart</i>. Ogni nodo si mette in attesa:<div class="separator" style="clear: both; text-align: center;">
<a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1VrZouJb2F85Kmo8TgldBXVk5IGMR54QKsSj41RyR4V5oGLSuwARPs9bNO2iPTkALX_BZVnEQRygUGqZW6kbs8-xWKIgLqIExrTjFbfTn2RUjJ9Ix8AISiEBXib3vG-TCRReaCh6Dn6SS/s1600/gg1.jpg" imageanchor="1" style="margin-left:1em; margin-right:1em"><img border="0" height="223" width="400" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj1VrZouJb2F85Kmo8TgldBXVk5IGMR54QKsSj41RyR4V5oGLSuwARPs9bNO2iPTkALX_BZVnEQRygUGqZW6kbs8-xWKIgLqIExrTjFbfTn2RUjJ9Ix8AISiEBXib3vG-TCRReaCh6Dn6SS/s400/gg1.jpg" /></a></div>
</li>
<li>importate le librerie di gridgain nel progetto e modificate il codice in modo da utilizzare gridgain per il calcolo:
<pre class="brush: scala">
def neper(iterations : Int) = {
grid !*~ (
for (w <- 1 to iterations) yield () => {
val ret = invFact(w)
println("Ricevuto: " + w + " - Restituito: " + ret)
ret
},
(s: Seq[BigDecimal]) => (BigDecimal(0) /: s)(_ + _)
)
}
def main(args : Array[String]) : Unit = {
scalar {
val n = neper(100);
println("e = " + n)
}
}
</pre>
</li>
</ol>
Se, per esempio, accendiamo un solo nodo, a parte quello da cui fate partire l'applicazione, quindi 2 nodi in tutto, vedrete che il carico si è suddiviso grosso modo a metà (il balancing viene fatto dinamicamente). L'output del nodo pricinpale è:
<pre style="font-size: 8pt; color: green;">
Ricevuto: 37 - Restituito: 7.265460179153071315382745030722890E-44
Ricevuto: 71 - Restituito: 1.175808554667930839412331276025168E-102
Ricevuto: 15 - Restituito: 7.647163731819816475901131985788074E-13
Ricevuto: 57 - Restituito: 2.467495709560789306494418417905353E-77
Ricevuto: 27 - Restituito: 9.183689863795546148425716836473919E-29
Ricevuto: 47 - Restituito: 3.866628513960593886829197697871059E-60
Ricevuto: 51 - Restituito: 6.446959640457172680454177834252131E-67
Ricevuto: 21 - Restituito: 1.957294106339126123084757437350544E-20
Ricevuto: 17 - Restituito: 2.811457254345520763198945583010321E-15
Ricevuto: 61 - Restituito: 1.970131956802168311835039121583386E-84
Ricevuto: 59 - Restituito: 7.210682961895936021316243184995189E-81
Ricevuto: 63 - Restituito: 5.043860616493006430709265544248299E-88
Ricevuto: 9 - Restituito: 0.000002755731922398589065255731922398590
Ricevuto: 31 - Restituito: 1.216125041553517949629974685692294E-34
Ricevuto: 19 - Restituito: 8.220635246624329716955981236872284E-18
Ricevuto: 53 - Restituito: 2.339245152560657721500064526216304E-70
Ricevuto: 35 - Restituito: 9.677592958631890992089816380922888E-41
Ricevuto: 77 - Restituito: 6.887854405285506994393217621555398E-114
Ricevuto: 67 - Restituito: 2.741896188035459954765761198513713E-95
Ricevuto: 85 - Restituito: 3.549744558233655586243013385073271E-129
Ricevuto: 81 - Restituito: 1.724992688482351758285854365654940E-121
Ricevuto: 99 - Restituito: 1.071510288125466923183546759519195E-156
Ricevuto: 97 - Restituito: 1.039579281539328008872677066085523E-152
Ricevuto: 83 - Restituito: 2.534517614578830088577511556942316E-125
Ricevuto: 13 - Restituito: 1.605904383682161459939237717015495E-10
Ricevuto: 25 - Restituito: 6.446950284384473396194853219204692E-26
Ricevuto: 55 - Restituito: 7.876246304918039466330183589953885E-74
Ricevuto: 7 - Restituito: 0.0001984126984126984126984126984126985
Ricevuto: 3 - Restituito: 0.1666666666666666666666666666666666
Ricevuto: 87 - Restituito: 4.744379254522394528525813131613567E-133
Ricevuto: 29 - Restituito: 1.130996288644771693155876457693833E-31
Ricevuto: 11 - Restituito: 2.505210838544171877505210838544173E-8
Ricevuto: 93 - Restituito: 8.644742106836940619829775373573826E-145
Ricevuto: 89 - Restituito: 6.057685462873333156953285408086779E-137
Ricevuto: 73 - Restituito: 2.237078680875058674680995578434491E-106
Ricevuto: 23 - Restituito: 3.868170170630684037716911931522814E-23
Ricevuto: 49 - Restituito: 1.643974708316579033515815347734293E-63
Ricevuto: 91 - Restituito: 7.396441346609686394326355809629767E-141
Ricevuto: 33 - Restituito: 1.151633562077195028058688149329824E-37
Ricevuto: 69 - Restituito: 5.843768516699616271879286441845085E-99
Ricevuto: 45 - Restituito: 8.359650847182803983324725422797232E-57
Ricevuto: 5 - Restituito: 0.008333333333333333333333333333333330
Ricevuto: 65 - Restituito: 1.212466494349280391997419601982764E-91
Ricevuto: 43 - Restituito: 1.655210867742195188698295633713852E-53
Ricevuto: 95 - Restituito: 9.680562269694222418622368839388382E-149
Ricevuto: 75 - Restituito: 4.030772397973078693118910952134216E-110
Ricevuto: 1 - Restituito: 1
Ricevuto: 39 - Restituito: 4.902469756513543397694159939759036E-47
Ricevuto: 41 - Restituito: 2.989310827142404510789121914487217E-50
Ricevuto: 79 - Restituito: 1.117795262136563939369233628944401E-117
Sum = 1.71828182845904523536028747135266241129844606162999606421881338461047508297046530851272129739288024500806666138654505778398426211369899599762685530664760916526029476793035635790672605174468695
[18:09:56] GridGain stopped OK [uptime=00:00:01:898]
</pre>
cioè ha eseguito 55 iterazioni. Le altre sono state eseguite dall'altro nodo (vi risparmio l'output, che vedreste nella sua console). Se a runtime avessi lanciato ancora un terzo nodo, si sarebbe preso il proprio carico di lavoro e tutto il sistema avrebbe scalato di conseguenza, <b>automaticamente</b>!
<p>Notare che sono stato comunque costretto a modificare il codice originario. Perché? Perché non ho fatto il bravo, cioé non ho utilizzato né un monad <i>writer</i> né un monad <i>state</i>. Li vedremo in un prossimo post. :)</p>
<p itemprop="reviewer">onof</p>
</div>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-15516502674380084842011-03-07T17:58:00.001+01:002011-03-10T12:56:28.237+01:00Codemotion 2011<div class="separator" style="clear: both; text-align: center;">
<a href="http://www.codemotion.it/sites/codemotion.it/files/image/codemotion_120_60(1).gif" imageanchor="1" style="clear:right; float:right; margin-left:1em; margin-bottom:1em"><img border="0" height="60" width="120" src="http://www.codemotion.it/sites/codemotion.it/files/image/codemotion_120_60(1).gif" /></a></div>
<p>I talk a cui ho assistito:
<ol>
<li itemscope itemtype="http://data-vocabulary.org/Review"><a href="http://www.codemotion.it/evento/talk-database-no-sql-anything-else" itemprop="itemreviewed">Database NO-SQL: Anything else? di Giorgio Desideri.</a><span itemprop="description">L'ho trovato interessante, soprattutto perché conosco poco <a href="http://cassandra.apache.org/">Cassandra</a>.</span> Voto: <span itemprop="value">7</span> su <span itemprop="best">10</span>.</li>
<li itemscope itemtype="http://data-vocabulary.org/Review"><a href="http://www.codemotion.it/evento/talk-html5-and-running" itemprop="itemreviewed">HTML5 Up and Running, di Marco Casario.</a> Molto bello, sono stati evidenziati i punti di forza e le difficoltà sul cammino di HTML5. Voto: <span itemprop="value">8</span> su <span itemprop="best">10</span>.</li>
<li itemscope itemtype="http://data-vocabulary.org/Review"><a href="http://www.codemotion.it/evento/talk-web-apps-mobile-flash-html-5adobe-c039%C3%A8" itemprop="itemreviewed">Web, Apps, Mobile, Flash Html 5...Adobe c'è! di Andrea Amadeo.</a> Le strategie di Adobe per il futuro. Voto: <span itemprop="value">7</span> su <span itemprop="best">10</span>.</li>
<li itemscope itemtype="http://data-vocabulary.org/Review"><a href="http://www.codemotion.it/evento/talk-l039azienda-oracle" itemprop="itemreviewed">L'azienda Oracle.</a> Niente di nuovo, più qualche rassicurazione sul futuro di Java. Voto: <span itemprop="value">6</span> su <span itemprop="best">10</span>.</li>
<li itemscope itemtype="http://data-vocabulary.org/Review"><a href="http://www.codemotion.it/evento/talk-distributed-programming-gridgain-and-scala" itemprop="itemreviewed">Distributed Programming with GridGain and Scala, di Nikita Ivanov.</a> La potenza espressiva di Scala in un framework molto promettente. Voto: <span itemprop="value">9</span> su <span itemprop="best">10</span>.</li>
<li itemscope itemtype="http://data-vocabulary.org/Review"><a href="http://www.codemotion.it/evento/talk-hacking-infinispan-new-open-source-data-grid-meets-nosql" itemprop="itemreviewed">Hacking Infinispan: the new open source data grid meets NoSQL, di Manik Surtani.</a> I punti di forza di <a href="http://www.jboss.org/infinispan">Infinispan</a>, presentati in modo molto puntuale. Da notare: in arrivo supporto per JPA! Voto: <span itemprop="value">8</span> su <span itemprop="best">10</span>.</li>
</ol>
</p>
<p>
Il talk che mi è piaciuto di più sicuramente quello su <a href="http://www.gridgain.com/">GridGain</a> (nei prossimi giorni seguirà un post dedicato :) ). A seguire, il talk di Marco Casario, molto bello: il suo libro su HTML5 non mancherà nella mia libreria.
</p>
<p>
Purtroppo non mi è stato possibile, ma avrei voluto vedere anche:
<ul>
<li><a href="http://www.codemotion.it/evento/talk-stato-dell039arte-del-mobile-game-programming-pubblicare-un-gioco-sugli-app-store-pochi-">Stato dell'arte del Mobile Game Programming: pubblicare un gioco sugli app store in pochi giorni, di Ugo Landini</a></li>
<li><a href="http://www.codemotion.it/evento/talk-sopravvivere-felicemente-ad-un-anno-e-mezzo-di-sviluppo-android">Sopravvivere felicemente ad un anno e mezzo di sviluppo Android, di Alfredo Morresi</a></li>
<li><a href="http://www.codemotion.it/evento/talk-perch%C3%A8-potresti-aver-bisogno-di-un-database-nosql-anche-se-non-sei-google-o-facebook">Perché potresti aver bisogno di un database NoSQL anche se non sei Google o Facebook di Luca Garulli</a></li>
</ul>
</p>
<p>Da parte mia ringrazio gli organizzatori e gli speakers, un ottimo evento.</p>Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-26159818845510222372011-03-04T23:21:00.003+01:002011-04-02T00:13:22.713+02:00Primo sguardo a GuiceDa una recente <a href="http://debasishg.blogspot.com/2011/03/pushing-envelope-on-oo-and-functional.html?showComment=1299170313724#c8614814323780197784">discussione sul blog di Debasish Ghosh</a>, mi è nata la curiosità di guardare <a href="http://code.google.com/p/google-guice/">questo container di cui avevo sentito parlare</a>.
Una caratteristica che mi ha colpito è il modo di definire come istanziare gli oggetti annotando un metodo, ad esempio in questo modo:
<pre class="brush: java">
public class OrderProcessingModule extends AbstractModule {
...
@Provides
IOrderRepository createRepo() {
RemoteOrderRepositoryAdapter repo = new
RemoteOrderRepositoryAdapter(ThirdPartyObject.getFoo());
repo.setStuff(ThirdPartyObject.instance.createStuff());
// ... altro codice per inizializzare repo
//
return repo;
}
}
</pre>
che, da quanto ho capito (ma ho fatto solo un analisi sommaria) è anche l'unico metodo per iniettare componenti di terze parti.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-29806254742024073462011-03-02T18:10:00.001+01:002011-04-02T00:14:16.048+02:00Leaky abstraction: Asp.Net MasterPageConsideriamo una pagina web in cui, cliccando su un elemento in una lista, vengono visualizzati alcuni controlli, che dipendono dal tipo di elemento cliccato. A design-time non è dato di sapere quali sono questi controlli, i quali, a loro volta, possono provocare postback. Sono necessari dei controlli dinamici.<br />
<span title="As Fair As I Know">AFAIK</span>, l'approccio migliore a questo problema è:
<ul>
<li>creazione dello <span style="font-family:courier">UserControl</span> in un evento della pagina</li>
<li>aggiunta del controllo in un <span style="font-family:courier">PlaceHolder</span></li>
<li>impostazione del path dello <span style="font-family:courier">UserControl</span> in un <span style="font-family:courier">HiddenField</span></li>
<li>nell'<span style="font-family:courier">OnInit</span> della pagina creazione del controllo a partire da <span style="font-family:courier">Request.Form</span>, per permettere il caricamento del <span style="font-family:courier">ViewState</span></li>
</ul>
ossia una cosa del genere:
<pre class="brush: csharp">
protected override void OnInit(EventArgs e) {
if(IsPostback) {
var currentView = Request.Form[CurrentViewHiddenControl.UniqueID];
if (!string.IsNullOrEmpty(currentView)) {
var control = LoadControl(currentView);
control.ID = "MyView";
PlaceHolder1.Controls.Add(control);
}
}
}
protected void OnSelected(Item item) {
PlaceHolder1.Controls.Clear();
var controlPath = GetControlPathByItem( item );
var control = LoadControl( controlPath );
control.ID = "MyView";
PlaceHolder1.Controls.Add(control);
CurrentViewHiddenControl.Value = controlPath;
}
</pre>
Ma non funziona se i controlli vengono creati in un <span style="font-family:courier">UpdatePanel</span> e la pagina ha una <span style="font-family:courier">MasterPage</span>; quello che succede è che il <b>primo</b> postback non viene gestito correttamente. <span style="color: red">E non c'è modo di farlo funzionare, se non togliendo la <span style="font-family:courier">MasterPage</span></span>. Ora, può anche darsi che esista qualche workaround molto tricky, ma <u>è assurdo che un normale processo, come il ciclo di vita di una pagina, venga stravolto da un dettaglio grafico</u> quindi MasterPage = <a href="http://www.joelonsoftware.com/articles/LeakyAbstractions.html">leaky abstraction</a>.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-60670457704023540282011-03-01T11:10:00.006+01:002011-04-02T00:18:06.109+02:00Scalaz: ricerche intelligenti con Burkhard-KellerUn'interessante applicazione di <a href="http://scalaz.googlecode.com">scalaz</a> è l'implementazione dell'algoritmo di Burkhard-Keller, utile per effettuare ricerche veloci basate sulla distanza. Ad esempio:<br /><br />
<pre class="brush: scala">
import scalaz._
import Scalaz._
object DoQuery {
def main(args: Array[String]) = {
val found = find(args(0))
println( found.mkString("Forse volevi dire: ",
" oppure ", "") )
}
def find( m : String) = {
// dizionario
val dictionary = List("Java", "Scala", "Haskell").bktree
// cerca nel dizionario gli elementi con distanza minore o uguale a 2
dictionary |=| (m, 2)
}
}
</pre>
<br /><br />che, lanciato con input <span style="font-family: Courier">Skala</span> restituisce:<br /><br /><pre><br />[info] <br />[info] == run ==<br />[info] Running bkTreeExample.DoQuery Skala<br />Forse volevi dire: Scala<br />[info] == run ==<br />[success] Successful.<br /></pre><br /><br />Sarebbe interessante capire se e come si possa integrare con <a href="http://scalaquery.org/">ScalaQuery</a> per interagire con un database.Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-14628183366166334962011-02-28T13:20:00.002+01:002011-02-28T13:24:08.545+01:00Codemotion: io ci sarò<a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="http://www.codemotion.it/"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 300px; height: 250px;" src="http://www.codemotion.it/sites/codemotion.it/files/image/codemotion_300_250.gif" border="0" alt="" /></a><br />Ci vediamo là!Unknownnoreply@blogger.com0tag:blogger.com,1999:blog-6200426339083146338.post-64805092903597362522011-02-27T22:38:00.013+01:002011-02-28T08:44:36.438+01:00Il DAL deve dipendendere dal BLL e non viceversa!Avete presente la classica applicazione three-tier?<br /><ol><br /><li>Presentation</li><br /><li>Business logic</li><br /><li>Data access</li><br /></ol><br />Molte volte, <em>troppe</em> volte, abbiamo visto dipendenze di questo tipo:<br /><br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUAoSEHnE848y5JG5VF-DqAROwHRWrs6hzjRFujCXhdZ36NmxX0QD60l8Cipla89N-loDKY0rN1jQh-yo4PDZw5el8uWtxNlXnBJx773x-Om2skdqhffr4boCC0TlgmD9OyUlUuTNl8mQS/s1600/wrong3t.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 152px; height: 284px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjUAoSEHnE848y5JG5VF-DqAROwHRWrs6hzjRFujCXhdZ36NmxX0QD60l8Cipla89N-loDKY0rN1jQh-yo4PDZw5el8uWtxNlXnBJx773x-Om2skdqhffr4boCC0TlgmD9OyUlUuTNl8mQS/s320/wrong3t.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5578491119870565810" /></a><br /><br />Io stesso avevo progettato applicazioni in questo modo, infatti risulta abbastanza naturale, per esempio, nel nostro strato di business logic scrivere qualcosa del genere (ovviamente orderRepository proviene dal DAL):<br /><br /><pre><br /> DAL.Order order = this.orderRepository.getOrder(id);<br /> OrderDTO orderDto = OrderDTO.createFrom(order);<br /></pre><br /><br />Ma in questo modo, se volessimo cambiare database come si fa? Una soluzione potrebbe essere quella di lasciare al DAL la responsabilità di gestire i differenti tipi di storage. Ma in ogni caso questo ci costringe a realizzare un business logic layer consapevole di come vengono salvati gli oggetti, cioè che nel DAL esiste un oggetto Order, (che probabilmente corrisponderà ad una tabella), quindi ci limita molto anche nella progettazione del DAL stesso. Non a caso questo tipo di architettura è il risultato del pericolosissimo <a href="http://uml-tutorials.trireme.com/uml_tutorial_2_1.htm">data-driven design</a>, cioè quella tecnica di sviluppo che prevede le fasi:<br /><ol><br /><li>design del database;</li><br /><li>reverse-engineering dello schema del db in classi, nel DAL;</li><br /><li>sviluppo di servizi che manipolano queste classi, nel BLL;</li><br /><li>realizzazione di interfacce che grosso modo riproducono i campi del database e le sue strutture.</li><br /></ol><br /><br />Ma il nocciolo dell'applicazione è il suo model, il suo business logic, non il suo storage. Se ci rendiamo conto di questo, dovrebbe essere l'accesso ai dati a dipendere dal business e non viceversa. Dunque come realizziamo la nostra architettura in questo modo:<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKRfqzvi2jrFPemjYZdswbsA5ftdcRMEeHenMlhLcAKywwCqaFG_2QGkEvHftJmZ7FNAzhu0CuKh3Ue_aeQEqj3TXA6QcqwtPprAWb7A210IMpso4dhan0QXg0mid-CSfN7AQTf19o141W/s1600/right3t.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 152px; height: 284px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgKRfqzvi2jrFPemjYZdswbsA5ftdcRMEeHenMlhLcAKywwCqaFG_2QGkEvHftJmZ7FNAzhu0CuKh3Ue_aeQEqj3TXA6QcqwtPprAWb7A210IMpso4dhan0QXg0mid-CSfN7AQTf19o141W/s320/right3t.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5578497869115933970" /></a><br />Come possiamo gestire l'accesso ai dati dal BLL? In questo ci viene incontro la dependency injection, in modo semplicissimo:<br /><ol><br /><li>nel BLL creiamo un'interfaccia IOrderRepository, che stavolta non ci restituirà degli oggetti che replicano la struttura del database ma i nostri veri oggetti di dominio;</li><br /><li>nel BLL creiamo il nostro servizio OrderService, con un riferimento a IOrderRepository;</li><br /><li>nel DAL, che dipende dal BLL, implementiamo IOrderRepository, il quale effettua la mappatura dal database al modello: è questo strato il responsabile di scelte come: usiamo un ORM? Salviamo su XML? Usiamo MongoDB?</li><br /><li>istruiamo il nostro dependency injection container con l'implementazione da iniettare in OrderService;</li><br /></ol><br />ed ecco fatto: abbiamo finalmente slegato totalmente il BLL dal DAL. Possiamo abbandonare il <span style="font-weight:bold;color:red;">diabolico </span>data-driven design.<br /><a onblur="try {parent.deselectBloggerImageGracefully();} catch(e) {}" href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoITDzP9chB14EnHszOeuutjpwOaz8WfFdFi37TqZHeXPPHzCAgeqm_s_LkbMhfUGTcpk63nj002RRh9SMy1pdcyUweJHJ8y6oZEksvmBGNTjDNPEKwxSX1WcTT7_j8F8ntJTITpBb4SSM/s1600/BllDal.png"><img style="display:block; margin:0px auto 10px; text-align:center;cursor:pointer; cursor:hand;width: 320px; height: 92px;" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoITDzP9chB14EnHszOeuutjpwOaz8WfFdFi37TqZHeXPPHzCAgeqm_s_LkbMhfUGTcpk63nj002RRh9SMy1pdcyUweJHJ8y6oZEksvmBGNTjDNPEKwxSX1WcTT7_j8F8ntJTITpBb4SSM/s320/BllDal.png" border="0" alt="" id="BLOGGER_PHOTO_ID_5578504965793887394" /></a>Unknownnoreply@blogger.com0