
by Randall Munroe (CC Attribution-NonCommercial 2.5)
public void compute(Runnable task)
interface Task extends Runnable, Serializable {}
public <T extends Runnable & Serializable> void compute(T task)
class Registry {
public void storeObject(Object obj) { }
public T getObject(Class<T> ofClass) {}
}
class Registry {
private Map<Class<?>, Object> objects = new HashMap<Class<?>, Object>();
public void storeObject(Object obj) {
objects.put(obj.getClass(), obj);
}
public <T> T getObject(Class<T> ofClass) {
Object instance = objects.get(ofClass);
return ofClass.cast(instance);
}
}
public interface ServiceLocator {
public Executor getExecutor();
}
class ServiceLocatorProps implements ServiceLocator {
private Executor executor;
public ServiceLocatorProps() throws Exception {
Properties props = new Properties();
props.load(getClass().getResourceAsStream("services.properties"));
String executorClassName = props.getProperty(
"java.util.concurrent.Executor");
Class<Executor> executorClass =
(Class<Executor>) Class.forName(executorClassName); //WARNING!!
this.executor = executorClass.newInstance();
}
public Executor getExecutor() {
return executor;
}
}
public ServiceLocatorProps() throws Exception {
Properties props = new Properties();
props.load(getClass().getResourceAsStream("services.properties"));
String executorClassName = props.getProperty(
"java.util.concurrent.Executor");
Class<?> loadedClass = Class.forName(executorClassName);
Class<? extends Executor> executorClass = loadedClass.asSubclass(Executor.class);
this.executor = executorClass.newInstance();
}
public class CollectionUtils {
public static List listWith(T... elements) {
return Arrays.asList(elements);
}
...
}
public static <K, V> Map<K, V> mapWith(Map.Entry<K, V>... entries) {
HashMap<K, V> map = new HashMap<K, V>();
for (Map.Entry<K, V> eachEntry : entries)
map.put(eachEntry.getKey(), eachEntry.getValue());
return map;
}
String[] sa = new String[10];
Object[] oa = sa;
oa[0] = new Integer(5);
Class<String>[] ca = new Class<String>[10];
Object[] oa = ca;
ca[0] = new Integer(8);
object StackTest {It really is pretty simple; the whole testing framework sits on a single 200-line file. But is also is a bit verbose, isn't it? All those inner classes, cluttering the code... I tried to simplify things a bit. Here is what I came up with:
import scala.testing.SUnit._
def main(args:Array[String]): Unit = {
val tr = new TestResult
new TestSuite(
new Test01,
new Test02,
).run(tr)
for(val f <- tr.failures())
Console println f
}
class Test01 extends TestCase("pushing an element onto an empty stack") {
override def runTest() = {
val stack = new Stack()
val element = "asdf"
stack push element
assertEquals(stack.peek(), element)
}
}
class Test02 extends TestCase("popping an element from a stack") {
override def runTest() = {
val stack = new Stack()
val element = "asdf"
stack push element
stack.pop()
assertEquals(stack.isEmpty, true)
}
}
}
import sorg.testing._;I think it looks better. Sort of like those DSLs that are so fashionable these days... But the really cool thing is that it only took a couple dozen lines of code and a couple of hours to extend SUnit. Mind you that someone really proficient in Scala could probably do it much more quickly. See the whole unit testing domain specific language: (the name is almost larger than the code itself :)
object StackTests extends Tests with ConsoleDriver {
test ("pushing an element onto an empty stack") {
val stack = new Stack()
val element = "asdf"
stack push element
assertEquals(stack.peek(), element)
}
test ("popping an element from a stack") {
val stack = new Stack()
val element = "asdf"
stack push element
stack.pop()
assertEquals(stack.isEmpty, true)
}
}
package sorg.testing;
import scala.testing.SUnit._;
abstract class Tests extends Test with Assert {
type TestExp = () => Unit;
var tests = List[Pair[String,TestExp]]();
def test(desc: String)(t: => Unit) : Unit = {tests = Pair(desc,()=>t) :: tests};
override def run(tr: TestResult) = {
for (val Pair(desc, expression) <- tests) new TestCase(desc) {
override def runTest() = {Console println "running (" + desc + ")"; expression()}
}.run(tr)
}
}
trait ConsoleDriver extends Test {
def main(args:Array[String]): Unit = {
val results = new TestResult
Console println "running tests..."
this.run( results )
if (!results.failures.hasNext)
Console println "Success!";
else {
Console println "The following tests failed:";
for(val each:TestFailure <- results.failures)
Console println (each.toString + ":\n" + each.trace);
}
}
}
It is important to realize the "components" are not technology, they are a customer requirement. Customers want to add on to their software system by adding a new component, and adding this component must not require that they change their existing system. It is like adding new speakers to a stereo system.Ou seja, componentes são nada mais que uma unidade de extensão e/ou substituição dinâmica de um sistema de software. O adjetivo "dinâmico" é uma daquelas palavras que são jogadas por aí em contextos tão diversos a ponto de perder o seu significado, mas a noção aqui é bem simples: estamos considerando alterações realizadas em ambiente de produção, feitas por operadores do sistema. A partir dessa caracterização, podemos dezfazer uma série de confusões:
In particular, controllers coordinate the models and views with the input devices and handles scheduling tasks. (...) Class Controller does include default scheduling behaviour...What motivated me to write this entry was Fowler's superb article on GUI architectures. In there you'll find a thorough discussion on MVC and its subsequent variants. It will be a chapter on the upcoming second volume of his Patterns of Enterprise Application Architecture.
public class Web2dot0 {
private List<String> buzzwords =
listWith("mashup", "AJAX", "bottom-up", "tagging");
private Map<Integer, String> strategy =
mapWith(pair(1, "Pretty AJAX UI"), pair(3, "profit!"));
...
}
public class CollectionUtils {
public static <E> List<E> listWith(E... items) {
return Arrays.asList(items);
}
public static <K, V> Map<K, V> mapWith(Map.Entry<K, V>... entries) {
HashMap<K, V> map = new HashMap<K, V>();
for (Map.Entry<K, V> eachEntry : entries)
map.put(eachEntry.getKey(), eachEntry.getValue());
return map;
}
public static <K, V> Map.Entry<K, V> pair(K key, V val) {
return new ImmutablePair<K, V>(key, val);
}
public static final class ImmutablePair<K, V> implements Map.Entry<K,V> {...}
...
}
Software entities are more complex for their size than perhaps any other human construct because no two parts are alike (at least above the statement level). If they are, we make the two similar parts into a subroutine--open or closed. In this respect, software systems differ profoundly from computers, buildings, or automobiles, where repeated elements abound.Uma diretriz importante no desenvolvimento de software é minimizar a repetição (uma formulação mais imperativa desse princípio veio dos pragmatic programmers - Don't Repeat Yourself - DRY - com acrônimo e tudo). Isso quer dizer que, ao menos em teoria, ao analisar um sistema de grande porte, todo detalhe é significativo; cada linha deve representar o produto de um trabalho intelectual. Compare com um grande arranha-céu**, por exemplo. Não se trata de menosprezar os construtores - certamente existem desafios consideráveis em projetos civís dessa escala - mas me parece claro que o trabalho intelectual para construir dois andares não é o dobro do envolvido na construção de apenas um. Não obstante, os pedreiros*** tem de suar a camisa para de fato botar estes tais andares em pé. Incrívelmente, muita gente não percebe essa diferença fundamental e tenta tratar programadores como trabalhadores braçais, limitados a seguir as instruções de um ser superior ocupando um cargo pomposo (atualmente "arquiteto" é popular, mas "analista de sistemas" já foi o título mais comum).
Much of the complexity that he [the software developer] must master is arbitrary complexity, forced without rhyme or reason by the many human institutions and systems to which his interfaces must conform. These differ from interface to interface, and from time to time, not because of necessity but only because they were designed by different people, rather than by God.Em outras palavras "it's the requirements, stupid!". Uma das qualidades do software é a precisão; qualquer programa faz exatamente o que o programador manda, e nada mais. E isso é ótimo, pois abre a possibilidade para enormes ganhos de qualidade ao automatizar processos de negócios. E também é aí que a porca torce o rabo****, pois é surpreendentemente complicado traduzir estes processos, e seus dados, em especificações que computadores consigam entender. Isso porque as informações difícilmente estão em formato suficientemente exato para alimentar o desenvolvimento de software; costumam ser imprecisas, ambíguas e, frequentemente, inexistentes. Essa é razão da pujança de empresas como a SAP e os outros 500 bilhões fabricantes de ERPs.*****
"For instance, if you want to get hold of an object that (you have to know) happens to be backed by the underlying database then what you do is obtain an entry point to the data, and search over it for the object you want. Unlike the navigation that you might expect to do in an object graph, instead you build...queries. (...)"Yes, building a whole query just to get hold of one object reference is too much trouble and a violation of DRY (parenthesis: this sort of thing eases somewhat this pain, minus all the factories and spurious abstractions). But I think he overlooks a bit the fact that often we really need to do a query. It's frequently part of the problem domain, not the solution domain, to put it in other (more pompous) words.
package cc;
import java.io.File;
import java.util.TimeZone;
import com.domainlanguage.time.*;
import com.domainlanguage.timeutil.Clock;
public class DeleteOldFiles {
public static void main(String[] args) {
Clock.setDefaultTimeZone(TimeZone.getDefault());
CalendarInterval lastWeek =
Duration.weeks(1).subtractedFrom(Clock.today()).through(Clock.today());
for (File f : new File("D:\\tmp\\backup").listFiles()) {
TimePoint lastModified = TimePoint.from(f.lastModified());
if (lastWeek.includes(lastModified))
f.delete();
}
}
}
I got this from a colleague: "As you may have noted, on Wednesday, at two minutes and three seconds after 1:00 in the morning, the time and date will be 01:02:03 04/05/06. Unless you are very young, or live a very long time, this is probably your one chance to observe this date. Whoop it up."
Pointers are like jumps, leading wildly from one part of the data structure to another. Their introduction into high-level languages has been a step backwards from which we may never recover. (Charles Hoare)
You can either have software quality or you can have pointer arithmetic, but you cannot have both at the same time. (Bertrand Meyer)E daí? Nada.