Friday 4 September 2009
Thursday 20 August 2009
Two new services for the web
One of the nicest things of the recent year’s development in the web has been the increasing availability of structured web services for specific needs, low cost, nice and easy to use. Some of these allow the providers of web sites and web applications to provide a richer service to their customers with little effort from the development/design point of view.
Two well known examples of such services which we use are Google Analytics and UserVoice. What they provide is quite different, but they share the fact that they require a minimal effort to get the service running, and they provide a lot of functionality in a friendly environment.
This actually has been happening for many years, but recently there are more and more, of good quality. I guess it is one of the features that vaguely contribute to the “Web 2.0 – web as a platform”.
We recently decided that we will not just be users of such services, but we will start providing our own. So what we are now developing in Open Lab? Well, we are actually creating two new such services, which could be useful for all designers, developers and providers of web sites and web applications. One will help improve the services offered and the interactivity of any web site, the other will ease feedback from your web applications. In both cases, we will require little effort to the web site designer/developer, and offer something which should be beautiful.
A major part of Open Lab is working on these new services, in particular Matteo Bicocchi: see
http://www.open-lab.com/mb.ideasTwo well known examples of such services which we use are Google Analytics and UserVoice. What they provide is quite different, but they share the fact that they require a minimal effort to get the service running, and they provide a lot of functionality in a friendly environment.
This actually has been happening for many years, but recently there are more and more, of good quality. I guess it is one of the features that vaguely contribute to the “Web 2.0 – web as a platform”.
We recently decided that we will not just be users of such services, but we will start providing our own. So what we are now developing in Open Lab? Well, we are actually creating two new such services, which could be useful for all designers, developers and providers of web sites and web applications. One will help improve the services offered and the interactivity of any web site, the other will ease feedback from your web applications. In both cases, we will require little effort to the web site designer/developer, and offer something which should be beautiful.
A major part of Open Lab is working on these new services, in particular Matteo Bicocchi: see
for some of the graphic features that our new services will use.
We hope to launch the beta program for this services before this autumn’s end; we'll announce it also here on the blog.
Friday 3 July 2009
Escape from basecamp
Latest Teamwork video promo produced by Open Lab.
Script by Pietro Polsinelli, design by Pino Panzarella.
View on YouTube: www.youtube.com/user/teamworksoftware
Script by Pietro Polsinelli, design by Pino Panzarella.
View on YouTube: www.youtube.com/user/teamworksoftware
Labels:
"project management",
design,
promo,
teamwork,
video
Wednesday 1 July 2009
Graphic design & Convention signage for BTO2008
After the success of the BTO 2008 first edition, for which we designed graphics, prints and convention signals, Open Lab is starting up the 2009 project edition.
Buy Tourism Online 2009, 16-17 November, Stazione Leopolda, Florence.
Other photos on flickr
BTO It’s a debate and a commercial marketplace for the demand and offer of online tourism
.
Buy Tourism Online 2009, 16-17 November, Stazione Leopolda, Florence.
Other photos on flickr
BTO It’s a debate and a commercial marketplace for the demand and offer of online tourism
.
Labels:
design,
exhibition,
florence,
print
Thursday 23 April 2009
Wednesday 15 April 2009
Tomcat configuration: multi hosting
We recently extended our web server farm and we went through Tomcat 6 configuration trying to optimize performance and memory usage, in particular for our Teamwork hosting service. We are quite satisfied of the final result, but it required quite an effort. During our research we found several tools and hacks that we would like to share. In particular we found it hard to configure multi hosting as documentation is lacking (see the references): here you'll find an example of how to configure multi hosting on Tomcat 6.
In order to set a multi host we need to act on server.xml (in a standard Tomcat installation you can find it in CATALINA_HOME/conf) and change some parameters.
The default form of parameters that we want to change is:
In this example there is a single host and it's localhost and its appBase is in the default Tomcat location webapps directory.
For ours settings we add our virtual host:
In this case the default Host is the same as before, localhost, but we added a new host "demo.twproject.com" and we specified the appBase that is different from Tomcat's default location. But notice that this setting is not enough to set a new virtual host: we have to create (if it doesn't exist you must create it ) an xml context file relative to our new host under
'CATALINA_HOME/conf/Catalina/hostName'.
You can notice that directory structure has a correspondence with the engine and host name, if you want to be more general you should write structure for virtual hosts as
'CATALINA_HOME/conf/EngineName/virtualHostName'
In our specific case the application 'demo.twproject.com' has to answer as root of our registered url, so we created a context file named 'ROOT.xml' under
'CATALINA_HOME/conf/Catalina/demo.twproject.com/',
and the context is:
As we have said before our web application is the main application (and default application) on our virtual host, so we have to put into a directory called ROOT. As you can see we have set the application path to empty simply because it is the main application.
In this way we can set more virtual hosts that respond to different urls.
We set max and min Java heap size allocation using 'tomcat6w.exe', as we are on a Windows server (but what we’ve done before is valid in general) and set max and min at the same size, so we can allocate definitely a portion of memory for the JVM. For other settings such as GC optimized for multiprocessor machines, policy for scavengers, optimizations for throughput we have set a system variable named CATALINA_OPTS with our configuration:
CATALINA_OPTS = -Xmn 600m -XX:-UseParallelOldGC -XX:+AggressiveOpts
In other systems like Linux we can set max and min java heap size adding to CATALINA_OPTS parameters -Xmx and -Xms with max and min heap size.
As web-applications manage utility we use Lambda probe, a useful tool for managing multiple web apps and get statistics on them and on the system:
Lambda Probe is easy to install on your Tomcat ( or other application-server ), because it is just a war that you deploy in your app-server.
References
Java
http://java.sun.com/performance/reference/whitepapers/tuning.html#section4.2.5
http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html
Tomcat 6
http://tomcat.apache.org/tomcat-6.0-doc/deployer-howto.html#A%20word%20on%20Contexts
http://tomcat.apache.org/tomcat-6.0-doc/virtual-hosting-howto.html
Lambda Probe
http://www.lambdaprobe.org/d/index.htm
@author Roberto Baldi and Pietro Polsinelli
In order to set a multi host we need to act on server.xml (in a standard Tomcat installation you can find it in CATALINA_HOME/conf) and change some parameters.
The default form of parameters that we want to change is:
In this example there is a single host and it's localhost and its appBase is in the default Tomcat location webapps directory.
For ours settings we add our virtual host:
In this case the default Host is the same as before, localhost, but we added a new host "demo.twproject.com" and we specified the appBase that is different from Tomcat's default location. But notice that this setting is not enough to set a new virtual host: we have to create (if it doesn't exist you must create it ) an xml context file relative to our new host under
'CATALINA_HOME/conf/Catalina/hostName'.
You can notice that directory structure has a correspondence with the engine and host name, if you want to be more general you should write structure for virtual hosts as
'CATALINA_HOME/conf/EngineName/virtualHostName'
In our specific case the application 'demo.twproject.com' has to answer as root of our registered url, so we created a context file named 'ROOT.xml' under
'CATALINA_HOME/conf/Catalina/demo.twproject.com/',
and the context is:
As we have said before our web application is the main application (and default application) on our virtual host, so we have to put into a directory called ROOT. As you can see we have set the application path to empty simply because it is the main application.
In this way we can set more virtual hosts that respond to different urls.
We set max and min Java heap size allocation using 'tomcat6w.exe', as we are on a Windows server (but what we’ve done before is valid in general) and set max and min at the same size, so we can allocate definitely a portion of memory for the JVM. For other settings such as GC optimized for multiprocessor machines, policy for scavengers, optimizations for throughput we have set a system variable named CATALINA_OPTS with our configuration:
CATALINA_OPTS = -Xmn 600m -XX:-UseParallelOldGC -XX:+AggressiveOpts
In other systems like Linux we can set max and min java heap size adding to CATALINA_OPTS parameters -Xmx and -Xms with max and min heap size.
As web-applications manage utility we use Lambda probe, a useful tool for managing multiple web apps and get statistics on them and on the system:
Lambda Probe is easy to install on your Tomcat ( or other application-server ), because it is just a war that you deploy in your app-server.
References
Java
http://java.sun.com/performance/reference/whitepapers/tuning.html#section4.2.5
http://java.sun.com/javase/technologies/hotspot/vmoptions.jsp
http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html
Tomcat 6
http://tomcat.apache.org/tomcat-6.0-doc/deployer-howto.html#A%20word%20on%20Contexts
http://tomcat.apache.org/tomcat-6.0-doc/virtual-hosting-howto.html
Lambda Probe
http://www.lambdaprobe.org/d/index.htm
@author Roberto Baldi and Pietro Polsinelli
Labels:
Tomcat multi host,
Tomcat vistual host
Tuesday 24 February 2009
Monday 29 September 2008
Some office space pictures
Friday 22 August 2008
Managing multiple databases transparently over Hibernate
The JBlooming platform supports “Managing multiple databases transparently over Hibernate”; this allows also in case of multiple databases to keep using the pages and web components without worrying about Hibernate sessions and transactions. The technique is explained on Hibernate’s wiki, here:
Here we provide some sample code, specific to JBlooming framework. The web.xml file should poit to two configuration files, comma separated.
ThreadLocalPersistenceContextCarrier.java
package org.jblooming.persistence;
...
public class ThreadLocalPersistenceContextCarrier {
private Operator operator;
public PersistenceContext currentPC;
public Map persistenceContextMap=new Hashtable();
...
PersistenceContext.java
package org.jblooming.persistence.hibernate;
...
public class PersistenceContext {
public Session session;
public PersistenceConfiguration persistenceConfiguration;
public static ThreadLocal threadLocalPersistenceContextCarrier = new ThreadLocal() {
protected ThreadLocalPersistenceContextCarrier initialValue() {
return null;
}
};
________________________________________
public PersistenceContext() {
this((Connection) null);
}
________________________________________
public PersistenceContext(Connection c) {
this(null, c);
}
________________________________________
/**
* this is not managed by the filter
*/
public PersistenceContext(String persistenceConfigurationName, Connection c) {
if (JSP.ex(persistenceConfigurationName))
persistenceConfiguration = PersistenceConfiguration.persistenceConfigurations.get(persistenceConfigurationName);
else
persistenceConfiguration = PersistenceConfiguration.getFirstPersistenceConfiguration();
Sniffer interceptor = null;
if (Fields.TRUE.equals(ApplicationState.getApplicationSetting(SystemConstants.AUDIT)))
interceptor = new Sniffer();
Throwable t = null;
try {
if (c != null && interceptor != null)
session = persistenceConfiguration.getSessionFactory().openSession(c, interceptor);
else if (c != null)
session = persistenceConfiguration.getSessionFactory().openSession(c);
else if (interceptor != null)
session = persistenceConfiguration.getSessionFactory().openSession(interceptor);
else
session = persistenceConfiguration.getSessionFactory().openSession();
session.beginTransaction();
} catch (Throwable e) {
t = e;
}
//by thowing the exception only if there is an exp AND session is null, in all other cases the external finally can close the session correctly
if (t != null && session == null)
throw new PlatformRuntimeException(t);
}
________________________________________
public PersistenceContext(Session session) {
this.session = session;
}
________________________________________
public static Connection getNewConnection() throws ClassNotFoundException, SQLException {
PersistenceConfiguration pcf = PersistenceConfiguration.getDefaultPersistenceConfiguration();
Class.forName(pcf.driver_class);
return DriverManager.getConnection(pcf.driver_url, pcf.db_user_name, pcf.db_user_psw);
}
________________________________________
private void close(boolean thereHasBeenAnException) throws PersistenceException {
boolean exceptionInCommit = true;
if (!thereHasBeenAnException) {
try {
if (session.getTransaction() != null) {
session.getTransaction().commit();
exceptionInCommit = false;
}
} catch (Throwable throwable) {
Tracer.platformLogger.error(throwable);
}
}
if (thereHasBeenAnException || exceptionInCommit) {
try {
if (session.getTransaction() != null) {
session.getTransaction().rollback();
}
} catch (Throwable throwable) {
Tracer.platformLogger.error(throwable);
}
}
try {
//as we are NOT using Hibernate managed context, in contrast with FrontControllerFilter, there is need after commit/rollbacdk to close session
session.close();
} catch (Throwable throwable) {
throw new PersistenceException(throwable);
}
}
________________________________________
public void checkPoint() {
if (session.isOpen()) {
Transaction currentTransaction = session.getTransaction();
if (session.isOpen() && currentTransaction != null && !currentTransaction.wasRolledBack()) {
session.flush();
currentTransaction.commit();
session.beginTransaction();
}
}
}
________________________________________
public void commitAndClose() throws PersistenceException {
close(false);
}
________________________________________
public void rollbackAndClose() {
try {
close(true);
} catch (PersistenceException e) {
}
}
________________________________________
public static PersistenceContext getDefaultPersistenceContext() {
return switchTo((String) null);
}
________________________________________
public static PersistenceContext switchToFirst() {
return switchTo(PersistenceConfiguration.getFirstPersistenceConfiguration().name);
}
________________________________________
public static PersistenceContext switchTo(Class persistentClass) {
PersistenceContext persistenceContext = get(persistentClass);
threadLocalPersistenceContextCarrier.get().currentPC = persistenceContext;
return persistenceContext;
}
________________________________________
public static PersistenceContext switchTo(String persistenceConfigurationName) {
// set last used as current
PersistenceContext pc = getByConfigurationName(persistenceConfigurationName);
threadLocalPersistenceContextCarrier.get().currentPC = pc;
return pc;
}
________________________________________
public static PersistenceContext get(Class persistentClass) {
String conf = null;
for (String confName : PersistenceConfiguration.persistenceConfigurations.keySet()) {
PersistenceConfiguration pcf = PersistenceConfiguration.persistenceConfigurations.get(confName);
if (pcf.getHibernateConfiguration().getClassMapping(persistentClass.getName()) != null) {
conf = confName;
break;
}
}
return getByConfigurationName(conf);
}
________________________________________
public static PersistenceContext get(IdentifiableSupport persistentObj) {
String className=PersistenceHome.deProxy(persistentObj.getClass().getName());
String conf = null;
for (String confName : PersistenceConfiguration.persistenceConfigurations.keySet()) {
PersistenceConfiguration pcf = PersistenceConfiguration.persistenceConfigurations.get(confName);
if (pcf.getHibernateConfiguration().getClassMapping(className) != null) {
conf = confName;
break;
}
}
return getByConfigurationName(conf);
}
________________________________________
public static PersistenceContext get(String className) {
PersistenceContext pc;
try {
pc = PersistenceContext.get((Class) Class.forName(className));
} catch (ClassNotFoundException e) {
throw new PlatformRuntimeException(e);
}
return pc;
}
________________________________________
private static PersistenceContext getByConfigurationName(String persistenceConfigurationName) {
//there could be already a closed session on it
ThreadLocalPersistenceContextCarrier localPersistenceContextCarrier = null;
// exists ThreadLocal?
if (threadLocalPersistenceContextCarrier.get() == null) {
localPersistenceContextCarrier = new ThreadLocalPersistenceContextCarrier();
threadLocalPersistenceContextCarrier.set(localPersistenceContextCarrier);
}
localPersistenceContextCarrier = threadLocalPersistenceContextCarrier.get();
// guess the right persistenceConfiguration Name
PersistenceConfiguration persistenceConfiguration;
if (JSP.ex(persistenceConfigurationName))
persistenceConfiguration = PersistenceConfiguration.persistenceConfigurations.get(persistenceConfigurationName);
else {
// if there is a current in use sedimented on threadlocal, give that
if (localPersistenceContextCarrier.currentPC != null)
persistenceConfiguration = localPersistenceContextCarrier.currentPC.persistenceConfiguration;
//no current sedimented on threadlocal, use the first, "main" one
else
persistenceConfiguration = PersistenceConfiguration.getFirstPersistenceConfiguration();
}
// exist a PersistentContext for this conf ?
PersistenceContext persistenceContext = localPersistenceContextCarrier.getPersistenceContext(persistenceConfiguration.name);
if (persistenceContext == null) {
persistenceContext = new PersistenceContext(persistenceConfigurationName, null);
localPersistenceContextCarrier.putPersistenceContext(persistenceContext);
System.out.println("Creating new pc thlocid:"+localPersistenceContextCarrier.hashCode());
} else {
// check if sessions are still good
if (persistenceContext.session != null && !(persistenceContext.session.isOpen())) {
persistenceContext = new PersistenceContext(persistenceConfigurationName, null);
localPersistenceContextCarrier.putPersistenceContext(persistenceContext);
System.out.println("Creating currupted new pc thlocid:"+localPersistenceContextCarrier.hashCode());
}
}
return persistenceContext;
}
}
Here we provide some sample code, specific to JBlooming framework. The web.xml file should poit to two configuration files, comma separated.
ThreadLocalPersistenceContextCarrier.java
package org.jblooming.persistence;
...
public class ThreadLocalPersistenceContextCarrier {
private Operator operator;
public PersistenceContext currentPC;
public Map
...
PersistenceContext.java
package org.jblooming.persistence.hibernate;
...
public class PersistenceContext {
public Session session;
public PersistenceConfiguration persistenceConfiguration;
public static ThreadLocal
protected ThreadLocalPersistenceContextCarrier initialValue() {
return null;
}
};
________________________________________
public PersistenceContext() {
this((Connection) null);
}
________________________________________
public PersistenceContext(Connection c) {
this(null, c);
}
________________________________________
/**
* this is not managed by the filter
*/
public PersistenceContext(String persistenceConfigurationName, Connection c) {
if (JSP.ex(persistenceConfigurationName))
persistenceConfiguration = PersistenceConfiguration.persistenceConfigurations.get(persistenceConfigurationName);
else
persistenceConfiguration = PersistenceConfiguration.getFirstPersistenceConfiguration();
Sniffer interceptor = null;
if (Fields.TRUE.equals(ApplicationState.getApplicationSetting(SystemConstants.AUDIT)))
interceptor = new Sniffer();
Throwable t = null;
try {
if (c != null && interceptor != null)
session = persistenceConfiguration.getSessionFactory().openSession(c, interceptor);
else if (c != null)
session = persistenceConfiguration.getSessionFactory().openSession(c);
else if (interceptor != null)
session = persistenceConfiguration.getSessionFactory().openSession(interceptor);
else
session = persistenceConfiguration.getSessionFactory().openSession();
session.beginTransaction();
} catch (Throwable e) {
t = e;
}
//by thowing the exception only if there is an exp AND session is null, in all other cases the external finally can close the session correctly
if (t != null && session == null)
throw new PlatformRuntimeException(t);
}
________________________________________
public PersistenceContext(Session session) {
this.session = session;
}
________________________________________
public static Connection getNewConnection() throws ClassNotFoundException, SQLException {
PersistenceConfiguration pcf = PersistenceConfiguration.getDefaultPersistenceConfiguration();
Class.forName(pcf.driver_class);
return DriverManager.getConnection(pcf.driver_url, pcf.db_user_name, pcf.db_user_psw);
}
________________________________________
private void close(boolean thereHasBeenAnException) throws PersistenceException {
boolean exceptionInCommit = true;
if (!thereHasBeenAnException) {
try {
if (session.getTransaction() != null) {
session.getTransaction().commit();
exceptionInCommit = false;
}
} catch (Throwable throwable) {
Tracer.platformLogger.error(throwable);
}
}
if (thereHasBeenAnException || exceptionInCommit) {
try {
if (session.getTransaction() != null) {
session.getTransaction().rollback();
}
} catch (Throwable throwable) {
Tracer.platformLogger.error(throwable);
}
}
try {
//as we are NOT using Hibernate managed context, in contrast with FrontControllerFilter, there is need after commit/rollbacdk to close session
session.close();
} catch (Throwable throwable) {
throw new PersistenceException(throwable);
}
}
________________________________________
public void checkPoint() {
if (session.isOpen()) {
Transaction currentTransaction = session.getTransaction();
if (session.isOpen() && currentTransaction != null && !currentTransaction.wasRolledBack()) {
session.flush();
currentTransaction.commit();
session.beginTransaction();
}
}
}
________________________________________
public void commitAndClose() throws PersistenceException {
close(false);
}
________________________________________
public void rollbackAndClose() {
try {
close(true);
} catch (PersistenceException e) {
}
}
________________________________________
public static PersistenceContext getDefaultPersistenceContext() {
return switchTo((String) null);
}
________________________________________
public static PersistenceContext switchToFirst() {
return switchTo(PersistenceConfiguration.getFirstPersistenceConfiguration().name);
}
________________________________________
public static PersistenceContext switchTo(Class persistentClass) {
PersistenceContext persistenceContext = get(persistentClass);
threadLocalPersistenceContextCarrier.get().currentPC = persistenceContext;
return persistenceContext;
}
________________________________________
public static PersistenceContext switchTo(String persistenceConfigurationName) {
// set last used as current
PersistenceContext pc = getByConfigurationName(persistenceConfigurationName);
threadLocalPersistenceContextCarrier.get().currentPC = pc;
return pc;
}
________________________________________
public static PersistenceContext get(Class persistentClass) {
String conf = null;
for (String confName : PersistenceConfiguration.persistenceConfigurations.keySet()) {
PersistenceConfiguration pcf = PersistenceConfiguration.persistenceConfigurations.get(confName);
if (pcf.getHibernateConfiguration().getClassMapping(persistentClass.getName()) != null) {
conf = confName;
break;
}
}
return getByConfigurationName(conf);
}
________________________________________
public static PersistenceContext get(IdentifiableSupport persistentObj) {
String className=PersistenceHome.deProxy(persistentObj.getClass().getName());
String conf = null;
for (String confName : PersistenceConfiguration.persistenceConfigurations.keySet()) {
PersistenceConfiguration pcf = PersistenceConfiguration.persistenceConfigurations.get(confName);
if (pcf.getHibernateConfiguration().getClassMapping(className) != null) {
conf = confName;
break;
}
}
return getByConfigurationName(conf);
}
________________________________________
public static PersistenceContext get(String className) {
PersistenceContext pc;
try {
pc = PersistenceContext.get((Class) Class.forName(className));
} catch (ClassNotFoundException e) {
throw new PlatformRuntimeException(e);
}
return pc;
}
________________________________________
private static PersistenceContext getByConfigurationName(String persistenceConfigurationName) {
//there could be already a closed session on it
ThreadLocalPersistenceContextCarrier localPersistenceContextCarrier = null;
// exists ThreadLocal?
if (threadLocalPersistenceContextCarrier.get() == null) {
localPersistenceContextCarrier = new ThreadLocalPersistenceContextCarrier();
threadLocalPersistenceContextCarrier.set(localPersistenceContextCarrier);
}
localPersistenceContextCarrier = threadLocalPersistenceContextCarrier.get();
// guess the right persistenceConfiguration Name
PersistenceConfiguration persistenceConfiguration;
if (JSP.ex(persistenceConfigurationName))
persistenceConfiguration = PersistenceConfiguration.persistenceConfigurations.get(persistenceConfigurationName);
else {
// if there is a current in use sedimented on threadlocal, give that
if (localPersistenceContextCarrier.currentPC != null)
persistenceConfiguration = localPersistenceContextCarrier.currentPC.persistenceConfiguration;
//no current sedimented on threadlocal, use the first, "main" one
else
persistenceConfiguration = PersistenceConfiguration.getFirstPersistenceConfiguration();
}
// exist a PersistentContext for this conf ?
PersistenceContext persistenceContext = localPersistenceContextCarrier.getPersistenceContext(persistenceConfiguration.name);
if (persistenceContext == null) {
persistenceContext = new PersistenceContext(persistenceConfigurationName, null);
localPersistenceContextCarrier.putPersistenceContext(persistenceContext);
System.out.println("Creating new pc thlocid:"+localPersistenceContextCarrier.hashCode());
} else {
// check if sessions are still good
if (persistenceContext.session != null && !(persistenceContext.session.isOpen())) {
persistenceContext = new PersistenceContext(persistenceConfigurationName, null);
localPersistenceContextCarrier.putPersistenceContext(persistenceContext);
System.out.println("Creating currupted new pc thlocid:"+localPersistenceContextCarrier.hashCode());
}
}
return persistenceContext;
}
}
Tuesday 15 July 2008
Java as a practical development framework
A great source of informal discussion of ideas and news in the IT world is the podcast at blog.stackoverflow.com of the forthcoming community programming answers’ site stackoverflow. The podcast is held by Joel Spolsky and Jeff Atwood, the first is too well known to need introduction, and Atwood is a open minded programmer who holds an interesting wide scoped IT blog, and is actually leading the new site development. I look forward to using Stackoverflow site when it goes live.
They have many strong opinions, and you may agree on something and disagree on something else, but to me at least they are fun to listen, as they are both undeniably smart, and are the kind of people that would be nice to have for dinner, which is not always true for developers (but not the ones working in Open Lab :-) ).
There is one of their opinions, sneaking in now and then, which I find particularly misleading, as I find it both outdated and wrong, and forcing it a bit, but not too much, it sums out as: good and practical oriented programmers (the good ones are those that studied C at the university (???)), are those that now are Windows programmers; the guys who studied Java and kept on with that, are either university freaks that pass their time speculating about trivialities, or lovers of complexity for the sake of it, who do trivial two table persistence by using horribly complex and slow combination of Enterprise Java Beans with on top some pattern implementations in bad code.
Well, first of all, nobody has been using Enterprise Java Beans (EJB) in the classical sense in Java for years and years (we’re all using Hibernate, which lead to a revision of the concept of EJB, but nobody really cares about EJB anymore). The fact that you didn’t study pointers and memory allocation through C does not mean that don’t have a deep conceptual approach to programming; if you want to see something deep on the connection between the JVM and its implementation, subscribe the great Javaspecialist mailing list.
To me there is a strong connection between productivity, quality of code and the features of your IDE. Jetbrain’s Intellij IDE for Java has made writing Java and web (html, Jsp, JavaScript) code and improving quality through refactoring very easy, and some of these features have been ported to the NET universe (Resharper). Same with Hibernate -> NHibernate, Lucene -> Lucene.NET; notice that the flow of innovation is from Java to the others, not the other way round. The Java server and web development environment is great right from a pragmatic perspective. There are many other good practical reasons to pick Java as your choice; e.g. the incredibly wide spectrum of tools and API available, that no one currently can compete with; add to that the widest possible o.s. and database compatibility, and the possibility of deployment at really low costs (Linux+Tomcat+MySQL). Java is not just the contemporary Cobol: it is also the contemporary Cobol, so that it is welcome also in enterprises. That is what is great about being a Java developer: you can use the same technology to answer the needs of corporations or just three guys' company. There are concrete, practical reason to pick it as your server side development platform. So if you are building a server side application where you need the possibility of wide IT integration, like our Teamwork, Java is a relevant factor and a good choice. It is not a question of loving Java or NET or PHP: there are concrete reasons to prefer Java, both as a developer and as a customer.
The (remaining) windows programmers never understood how such an unlikely competitor as Java and Sun (yes, I know that IBM, Oracle helped..) came to win the programming language battle, but that is not a good reason to ignore this. Or how such an uncomfortable server o.s. like Linux became dominant on the server side, but that too can’t be ignored. So writing apps that don’t run in such environments, or that don’t have a really virtual virtual machine, is a not very pragmatic choice in general; with NET you are making a niche choice, which may be fine in some circumstances, but you surely can’t claim to be a paradigm of pragmatism. For an interesting (and informed) praising and critical perspective on Java, see Bruce Tate’s Beyond Java.
And a final note about studying C: that is actually one of the big problems that we have in Open Lab in job interviews: that people come out from Italian engineering university having studied just C as a programming language, and so are by now at galactic distance from the reality of programming today, and have to be tought practically everything from scratch. So actually still teaching C is very bad sign, a symptom of the obsolescence of our universities... .
Pietro Polsinelli
They have many strong opinions, and you may agree on something and disagree on something else, but to me at least they are fun to listen, as they are both undeniably smart, and are the kind of people that would be nice to have for dinner, which is not always true for developers (but not the ones working in Open Lab :-) ).
There is one of their opinions, sneaking in now and then, which I find particularly misleading, as I find it both outdated and wrong, and forcing it a bit, but not too much, it sums out as: good and practical oriented programmers (the good ones are those that studied C at the university (???)), are those that now are Windows programmers; the guys who studied Java and kept on with that, are either university freaks that pass their time speculating about trivialities, or lovers of complexity for the sake of it, who do trivial two table persistence by using horribly complex and slow combination of Enterprise Java Beans with on top some pattern implementations in bad code.
Well, first of all, nobody has been using Enterprise Java Beans (EJB) in the classical sense in Java for years and years (we’re all using Hibernate, which lead to a revision of the concept of EJB, but nobody really cares about EJB anymore). The fact that you didn’t study pointers and memory allocation through C does not mean that don’t have a deep conceptual approach to programming; if you want to see something deep on the connection between the JVM and its implementation, subscribe the great Javaspecialist mailing list.
To me there is a strong connection between productivity, quality of code and the features of your IDE. Jetbrain’s Intellij IDE for Java has made writing Java and web (html, Jsp, JavaScript) code and improving quality through refactoring very easy, and some of these features have been ported to the NET universe (Resharper). Same with Hibernate -> NHibernate, Lucene -> Lucene.NET; notice that the flow of innovation is from Java to the others, not the other way round. The Java server and web development environment is great right from a pragmatic perspective. There are many other good practical reasons to pick Java as your choice; e.g. the incredibly wide spectrum of tools and API available, that no one currently can compete with; add to that the widest possible o.s. and database compatibility, and the possibility of deployment at really low costs (Linux+Tomcat+MySQL). Java is not just the contemporary Cobol: it is also the contemporary Cobol, so that it is welcome also in enterprises. That is what is great about being a Java developer: you can use the same technology to answer the needs of corporations or just three guys' company. There are concrete, practical reason to pick it as your server side development platform. So if you are building a server side application where you need the possibility of wide IT integration, like our Teamwork, Java is a relevant factor and a good choice. It is not a question of loving Java or NET or PHP: there are concrete reasons to prefer Java, both as a developer and as a customer.
The (remaining) windows programmers never understood how such an unlikely competitor as Java and Sun (yes, I know that IBM, Oracle helped..) came to win the programming language battle, but that is not a good reason to ignore this. Or how such an uncomfortable server o.s. like Linux became dominant on the server side, but that too can’t be ignored. So writing apps that don’t run in such environments, or that don’t have a really virtual virtual machine, is a not very pragmatic choice in general; with NET you are making a niche choice, which may be fine in some circumstances, but you surely can’t claim to be a paradigm of pragmatism. For an interesting (and informed) praising and critical perspective on Java, see Bruce Tate’s Beyond Java.
And a final note about studying C: that is actually one of the big problems that we have in Open Lab in job interviews: that people come out from Italian engineering university having studied just C as a programming language, and so are by now at galactic distance from the reality of programming today, and have to be tought practically everything from scratch. So actually still teaching C is very bad sign, a symptom of the obsolescence of our universities... .
Pietro Polsinelli
Sunday 8 June 2008
Open Lab in the Apple!
Finally we have finished the CodeChecker for Mac! It is a spell checker for Word on Macs, using our minoritarian languages web service.
It was a long journey along the path of AppleScript's philosophy and it was quite instructive for us to learn development in the Mac World.
We realized that Applescript has big
potentials as an automation language, but translating complex macros with various data structures in Applescript wasn't a simple task.
X-code is a powerful development tool, however it doesn't offer useful features like code-completion on Applescript, because Applescript’ structure makes it hard to create an efficient code completion tool; we managed without.
Throughout development path we realized that Applescript offers developers flexible solutions, like using calls to other scripting languages like Python or Perl, and this feature was fundamental for some CodeChecker features.
Another powerful tool that we used in developing CodeChecker was InterfaceBuilder, to 'build' a nice Cocoa user friendly interface, and it worked well. CodeChecker has a nice Mac style interface, with a sliding panel for configuration. InterfaceBuilder is very useful and quite simple to use, moreover integration between X-Code and InterfaceBuilder is quite natural.
Finally we had to pack the application:
the last step was to make a installer simple to use
and do a complete installation of our product
with the possibility of multiple choices for various type of installations;for this work we used Package Maker, another Mac tool for developing Mac installers, and I must admit that it did what it had to very well!
The final evaluation of this Mac development work is quite positive, if we exclude some initial bad experiences due to limited knowledge of the
local hacks; now we can go much faster.
Roberto Baldi
Matteo Bicocchi
It was a long journey along the path of AppleScript's philosophy and it was quite instructive for us to learn development in the Mac World.
We realized that Applescript has big
potentials as an automation language, but translating complex macros with various data structures in Applescript wasn't a simple task.
X-code is a powerful development tool, however it doesn't offer useful features like code-completion on Applescript, because Applescript’ structure makes it hard to create an efficient code completion tool; we managed without.
Throughout development path we realized that Applescript offers developers flexible solutions, like using calls to other scripting languages like Python or Perl, and this feature was fundamental for some CodeChecker features.
Another powerful tool that we used in developing CodeChecker was InterfaceBuilder, to 'build' a nice Cocoa user friendly interface, and it worked well. CodeChecker has a nice Mac style interface, with a sliding panel for configuration. InterfaceBuilder is very useful and quite simple to use, moreover integration between X-Code and InterfaceBuilder is quite natural.
Finally we had to pack the application:
the last step was to make a installer simple to use
and do a complete installation of our product
with the possibility of multiple choices for various type of installations;for this work we used Package Maker, another Mac tool for developing Mac installers, and I must admit that it did what it had to very well!
The final evaluation of this Mac development work is quite positive, if we exclude some initial bad experiences due to limited knowledge of the
local hacks; now we can go much faster.
Roberto Baldi
Matteo Bicocchi
Tuesday 8 April 2008
Monday 7 April 2008
Integrating OSX clients and JBlooming web services
Recently I started to study AppleScript in order to translate a Visual Basic macro for Microsoft Word into AppleScript for Mac Word 2007. The decision to adopt AppleScript was taken because Mac Word doesn't use Visual Basic for macro since from Mac Word 2007. CodeChecker is the macro on which I'm working, it performs text correction using our on line dictionary web service (in the Smallcodes project). The main features of this code checker macro lay in the language where it performs correction, it uses dictionaries of minority languages like Ladin, Occitan, Ghedina. In our CodeChecker script we used SOA technology, that requires a particular library under Windows (SOA webkit 3.0), under Mac osx that library doesn't exist , but it was not a problem, because Applescript has a tool to generate the stub! Myracolous! The first approach with Applescript was quite traumatic because the syntax' logic is completely different from other script languages, it is oriented to a no programmers' audience for sure, in fact most of standard constructs like assignment or declaration is quite out of programming standards. I have to admit that it is a quite powerful scripting language, it allows complete control on system functions, you can also control single applications and use all system libraries, call other scripts made in other languages like Python or Perl and use the result inside the caller Applescript. In first instance Applescript was made to supply some standard system operations like batch operations using automator, but in recent years it was adopted as the scripting language for Microsoft office suite.
Roberto Baldi
Roberto Baldi
Wednesday 2 April 2008
A fundamental contribution: Murphy's laws AIR component
Teamwork sites SEO friendly - with Webwork
Webwork is now SEO friendly! In only two weeks, the Webwork team released a SEO friendly version of the tool, with which we published the new Teamwork site. :-)
Friendly SEO urls, no 301 redirects, no duplicated keywords, compositional titles... nice!
Friendly SEO urls, no 301 redirects, no duplicated keywords, compositional titles... nice!
Monday 17 March 2008
A content management system which is a good tool for SEO
Open Lab's content management system (CMS), Webwork, is in these days under scrutiny as a tool for Search Engine Optimization (SEO). SEO is an interesting and dynamic field, and after a while of study I noticed a peculiarity: the most indexable site is a static one, but in order to be able to dynamically optimize a site for SEO, you need to have it dynamically generated.
So a step towards SEO is to generate and manage your site with a CMS, but then add functionality to your CMS to generate pages optimal for SEO. For example, it is better to have plain friendly url named and pointing to sections of you web sited, then a constant url with just an id parameter changing all the time. Very bad is
So a step towards SEO is to generate and manage your site with a CMS, but then add functionality to your CMS to generate pages optimal for SEO. For example, it is better to have plain friendly url named and pointing to sections of you web sited, then a constant url with just an id parameter changing all the time. Very bad is
- getting the same document with different urls
- links not in href but just in onclicks
- having the same metatags on all pages
Tuesday 11 March 2008
Opening
I have the pleasure of opening the developer's blog of the Teamwork, Webwork, Smallcodes and Flowork applications, all built over the JBlooming platform.
We have used for quite a while Teamwork's blog also as a developers blog, but by now its time to dedicate a blog exclusively to technical issues.
Started in 2001 as a 4 friends startup company, Open Lab has been growing steadily in these seven years. We first made a leap by acquiring two other software houses in 2003 and 2004; now we are making our second leap, by putting together an enlarged development team and a prettier workplace. We'll call it <big>OpenLab</big>.
Open Lab is a rare case of an Italian IT company which is not a service company, but a real software house, with products like Teamwork, used today in 35 countries, and winner in 2007 of a Jolt Award, or Smallcodes, used by 10 different linguistic communities.
By real software house I mean not only what we do, but how: workplace quality, powerful tools, state of the art technology, a balanced male/female production team, team meetings, no overwork, pair programming, all contributes to the construction of a real, solid sotware house.
Pietro Polsinelli
Subscribe to:
Posts (Atom)