Rumble in the jungle: J2EE versus .Net

With the advent of .Net, Microsoft Corp. introduced an enterprise computing platform able to compete toe-to-toe with Sun Microsystems Inc.’s J2EE (Java 2 Platform, Enterprise Edition). Microsoft’s move leaves J2EE developers with two options: ignore .Net or analyze it. In this article, we choose the latter, analyzing and comparing the two technologies.

Both platforms feature innovative ideas–ideas that should cross pollinate, not stagnate on one specific platform. Furthermore, we all want technologies that add the best business value and are cutting edge, not bleeding edge! So, which language works better–.Net’s C# or Java? Is .Net poised to sweep all before it or is Microsoft’s mighty marketing machine simply desperate to make you think so? Well, we’ll dive into the technologies to find out.

What is J2EE?

When thinking of the Java 2 Platform, Enterprise Edition, the key word is platform. Java represents more than just a programming language, as it encompasses the VM technology that lets compiled Java programs run unaltered on various machine architectures; tools to compile, analyze, debug, and deploy Java programs; and other components, such as browser plug-ins, rich media, and more. Talk about feature creep!

The three faces of Java

About two years ago, Sun reorganized the Java platform into three profiles:

– The Java 2 Platform, Micro Edition (J2ME), for handheld and other lower-end devices

– The Java 2 Platform, Standard Edition (J2SE), targeted at desktop machines

– The Java 2 Platform, Enterprise Edition (J2EE), installed on servers and responsible for the heavy lifting in the Java world.

– Although it’s something of a simplification, you can think of J2ME as a subset of J2SE and J2EE as a superset of J2SE.

Our J2EE definition

Definition: J2EE is a Java-based technology stack, built on top of J2SE, that provides developers with the development tools and runtime capabilities necessary to build enterprise applications meeting rigorous uptime, security, scalability, and maintainability requirements.

The latest version of J2EE is 1.3. Sun uses the J2EE platform to synchronize the constituent technology specifications for specific releases. Here’s a partial J2EE components list:

JavaServer Pages (JSPs): Generate dynamic content for Web browsers and mobile devices. JSPs resemble HTML, especially when developers use custom tag libraries to remove Java code from the JSPs themselves, making them easier to maintain.

Servlets: Build control and navigation logic into J2EE applications, typically following a Model-View-Controller design pattern in conjunction with JSPs.

Enterprise JavaBeans (EJBs): The mainstay of the J2EE platform. There are two main types of EJB: session beans that model business logic and entity beans that model persistent data. When coded correctly, EJBs provide transparent scaling, a security framework, a transaction model, and a container-managed life cycle.

Java Connectivity Architecture (JCA): Lets Java enterprise applications interface with existing non-Java enterprise applications like SAP. Specifically, transactions and security roles can propagate, allowing you to fully utilize legacy applications in a J2EE architecture.

Java Message Service (JMS): Provides asynchronous messaging capabilities to the J2EE platform. Established message-oriented middleware (MOM) vendors like IBM (MQ Series) and Tibco (Rendezvous) provide JMS faces to their products.

Java Management Extensions (JMX): Manages J2EE servers and applications.

Java Naming and Directory Interface (JNDI): A required part of the J2EE platform, JNDI provides component location transparency in a clustered J2EE environment.

Although the following components are technically part of J2SE, they prove important for J2EE applications as well:

Java Database Connectivity (JDBC): The real bread and butter of any enterprise application! JDBC handles all database input/output via SQL.

The HotSpot Virtual Machine: Can run in server mode to better profile long-running applications with stringent requirements for thread and memory management. The HotSpot VM has addressed most of the initial concerns about J2EE’s performance.

The Java community: Spirit and ethos

In addition to these technologies, the Java platform boasts another important feature: the Java developer community.

With Java, you’ll find free, open source tools, such as Ant (a build tool), JUnit (a testing framework), JBoss (an application server), and NetBeans (an integrated development environment, or IDE). More exist–SourceForge lists hundreds of Java-related initiatives.

Moreover, look at the curriculum for any third-level teaching institution. In many such schools, students learn programming by studying Java. The same phenomenon pushed Unix from a 1970s research curiosity to the operating system that it is today. What’s my point? The students of today are the programmers of tomorrow, and they are learning in Java and Unix.

What is .Net?

So what exactly is .Net? Unlike J2EE’s specification set, .Net is a suite of shipping products (although some parts of .Net have been ratified as international standards by the European Computer Manufacturers Association (ECMA)).

According to Microsoft, “.Net is a set of Microsoft software technologies for connecting your world of information, people, systems, and devices.”

Well, that clears things up! The truth is, .Net evades easy definition because it covers so many topics. Some define it as a development platform for building XML Web services, while others think it’s a set of enterprise servers. Both lines of thinking prove correct, although neither tells the whole story. To get a clearer picture, let’s peek at .Net’s basic elements:

Smart client software: Software for running a variety of smart clients, from personal computers (Windows XP), to small-footprint devices like PDAs (Windows CE .Net), to set-top devices (Windows XP Embedded).

XML Web services: Let applications share data and consume services provided by other applications without regard to how those applications were built, what platform they run on, or what devices access them. .Net includes implementations of the latest accepted Web service standards, such as the XML Schema standard. In addition, Microsoft plans to provide many commercially available foundation services, called My Services, to serve as application building blocks. As a recent example, the MapPoint.Net Web service integrates maps and driving directions into applications. (That effort, however, has recently lost some momentum because partners have been slow to jump on board.)

Enterprise servers: Products that support enterprise applications by addressing different parts of the overall solution. Among the offerings in the mix are Application Center for deploying and managing Web applications, BizTalk Server for coordinating XML-based business processes across applications and organizations, and the SQL Server database application.

Development tools and the runtime environment: Includes Visual Studio .Net, a single integrated development environment for building .Net applications, along with the .Net Framework, which in turn includes the Common Language Runtime (CLR), ASP.Net (a new Web development environment for building Web applications and XML Web services), and an extensive set of framework class libraries.

Line them up

In this section, we show how J2EE and .Net solve common issues developers face when architecting a system. To help frame the discussion, we present each issue within the context of the layer where it is most relevant. The four layers we’ll cover are presentation, business, data, and runtime.

How do the two competitors handle HTML generation?

J2EE: JSPs and servlets generate HTML for J2EE applications. The servlet containers include such features as session state, a security framework, and configuration. Tag libraries allow the developer to cleanly separate presentation code from control and business logic and also make the JSPs readable to HTML coders. A new initiative called JavaServer Faces aims to extend JSPs to allow developers to specify UI (user interface) components, event handling for HTML widgets, data validation, and navigation. Currently, you can handle such tasks with presentation frameworks such as Struts, Webwork, or wingS.

.Net: ASP.Net builds and hosts Web applications under Microsoft’s Internet Information Server (IIS). ASP.Net includes the usual stuff: fault-tolerant session state, authentication and authorization, and HTML generation. With ASP.Net, developers build ASPX pages that include HTML and custom tags that map to server-side Web controls. Web controls encapsulate reusable user interface logic and provide many advanced features to ease Web programming. For example, input controls (e.g., textboxes) automatically maintain their state from one round trip to the next, so developers can access form data on the server via control properties (e.g., textbox.Text).

Web application overview

For the Ice Cold Beer Boutique application, we chose a problem interesting enough to be nontrivial, yet simple enough to ensure that we can clearly show each technologies’ features and deficits. With that in mind, what should the ICBB application accomplish?

The Ice Cold Beer Boutique

ICBB, a business-to-business (B2B) company that sells premium beverages to resellers in Europe and the US, wants to reduce costs and order turnaround time by allowing resellers to create orders on a secure Website. The IT strategy calls for incrementally building up the site as demand increases.

The application’s first release must:

– Be secure by allowing only authorized visitors access the ICBB Website

– Be easy to use; ICBB’s CEO intends to test this feature himself

– Allow resellers to view all currently stocked beverage types and prices

– Allow an ICBB system administrator to update the details for a beverage type

– Allow an ICBB system administrator to delete a beverage product

The second release, building on that functionality, will allow resellers to create orders and schedule them for shipment. Eventually, ICBB will integrate its Web store with its enterprise resource planning (ERP) system Sales order Processing module so sales invoices can be raised automatically and stock information updated.

Our goal: Produce an application using a technology and design that meets these immediate requirements and admits constant enhancements as the system expands.

Application structure

We implement a thin slice of the overall application, so you can see how the application layers communicate together.

J2EE notes

Let’s see how to design the ICBB application as a J2EE application, then look at the reasons behind the important J2EE-based implementation decisions.

The presentation tier

Unlike .Net, with J2EE you can employ a number of free frameworks to help build an application. That’s both good and bad: While I have freedom of choice, I may choose the wrong tool. For example, with Web frameworks, I can choose to build my own or choose between Struts, WebWork, Velocity, Turbine–jeez! Which one is the right one? It depends on the task at hand!

For our ICBB example, I chose the Jakarta Project’s Struts Web framework as it is arguably the most deployed Web framework in the J2EE world. Such wide deployment means that more developers know Struts than any other framework, Struts boasts a large and stable developer community, all the major application servers support Struts, and documentation/support is easy to come by. In short, you can expect Struts to be a long-lived Web application framework.

When using Struts, the system JSPs (JavaServer Pages) handle only data formatting and presentation. The pages themselves remain as simple as possible by using Jakarta Project standard tag libraries. These tag libraries require JSP 1.2 specification support, contained in all J2EE 1.3-compliant servers.

With tag libraries, Java code exists away from the JSPs, making the pages much easier to read and maintain. In addition, with tag libraries you can more easily change the JSPs’ look and feel.

Business and data tiers

I implement the business and data tiers as one unit using stateless session beans called the ProductManager and CategoryManager. These session beans retrieve requested products and categories from the database, delete products, and apply changes made to products by an ICBB system administrator. They also update the database using straight SQL executed as Java Database Connectivity (JDBC) code. SQL statements execute as PreparedStatement objects to allow JDBC drivers to optimize them as cacheable statements in the database wherever possible.

In a more complex system, I would split the ProductManager between session beans for business functionality and entity beans for persistence, but the business case for ICBB simply doesn’t warrant that approach–yet. Looking forward, I could easily extend the ProductManager session bean to delegate persistence to a separate persistence object(s).

Further, container managed transactions provide the system with transactional capability. Each business method invoked on the ProductManager class executes with a Required transaction attribute, and the Enterprise JavaBean (EJB) container manages the in-depth transaction management details.

Common services

Any serious enterprise computing platform must do the simple things well. In this section, we examine the most common bread and butter tasks in enterprise application development and how the J2EE-based ICBB sample application meets the following needs:

Exception handling: ICBBException indicates when an unexpected error occurs. ICBBExceptions are logged at the source to aid finding and fixing the underlying cause.

In the presentation tier, JSPs provide specific error-handling support through the attribute in the page directive. JSPs with that tag act as error handlers for other JSPs for use in application-wide error reporting and handling. See ExceptionHandler.jsp for a concrete example.

Logging: The code base uses the log4j logging library in conjunction with the Logger wrapper class to provide a library-independent logging system view. Log4j supports multiple destinations for logging information, including flat file, XML output, console and socket output, and even the Windows Event logger. In contrast to .Net, no explicit distinction exists between logging and trace output in J2EE, although your chosen server vendor may employ nonstandard features to provide trace information. Like .Net, the logging level can vary dynamically to aid debugging production systems while minimizing the overall impact on performance.

Configuration: Server-side components such as servlets and EJBs can also store configuration information outside code via the web.xml and ejb-jar.xml files. The ServletConfig for servlets and the ” java:comp/env” JNDI (Java Naming and Directory Interface) naming context for EJBs enable access to that configuration information.

Authentication: The servlet container’s built-in capabilities handle user authentication based on users’ established roles. By simply setting up protected resources in a declarative fashion, we can hand off the authorization and authentication responsibilities to the servlet container. See the etc/web.xml file for more details on this functionality (specifically the , , and tags).

Authorization: The J2EE specification strongly supports both declarative and programmatic security through APIs and XML configuration files. The ICBB application includes two roles: reseller and admin. J2EE’s declarative security features prevent nonadmin users from editing products, while its programmatic features control what a user sees on a particular JSP based on his or her current role.

Session management: The servlet/JSP specifications’ session management support lets developers create sessions and track users either through cookies or URL rewriting, while both JSPs and servlets can access the HttpSession object. The servlet container can invalidate these HTTP sessions automatically after a specified time-out period or programmatically (by calling the session.invalidate() method).

J2EE tools

As with application servers, J2EE developers can choose among a wide range of free and commercial tools to enhance their productivity. My favorites include:

Ant (free): The standard build tool for compiling, packaging, and deploying Java-based software.

JUnit (free): A simple, easy-to-use unit testing framework for Java.

xdoclet (free): Use custom Javadoc tags to generate code, XML, and so on from Java source code. I used xdoclet to generate some of the code and deployment descriptors for ICBB J2EE solution.

Eclipse (free): A good Java IDE (integrated development environment). Achieves native code performance in Java! Supports debugging via the Java Platform Debugging Architecture (JPDA), including debugging server-side components, plus productivity features such as smart coding help, Ant and JUnit integration, some source-code management integration, refactoring, and more.

IntelliJ (commercial): Another good Java IDE. Also provides debugging support through the JPDA, plus useful productivity features such as smart coding help, Ant and JUnit integration, source-code management integration, and refactoring.

Application server selection and portability

I chose IronFlare’s Orion application server to run the J2EE-based ICBB application. Orion boasts a small download size, supports the standard J2EE specifications, and is easy to set up and develop on. Orion also supports application hot deployment and is 100% Pure Java, so it runs on any platform with a JDK.

You can choose from numerous alternatives, such as JBoss, BEA Systems Inc.’s WebLogic, or IBM Corp.’s WebSphere. For me, Orion’s ease of use, size, and speed make it a good choice for this project. If you want to deploy the application on other application servers, feel free. I used xdoclet to generate the server-specific pieces, such as the deployment descriptors, easing the porting process. In addition, I used no proprietary Orion features to build the sample application.

Data validation

Since the J2EE-based ICBB implementation uses Struts, I can hand off most of the data validation work to Strut’s behind-the-scenes code. For each HTML form from which I want to update the system, I define a class that extends ActionForm, such as EditForm. Then I implement the validate method to handle whatever necessary validation before the associated Struts Action fires. Note that the data validation is server-side; to enforce client-side validation of particular fields, I would have used the Jakarta Project’s Validate tag.

Caching strategies

For Web applications, caching refers to the storing and reuse of previously constructed HTML fragments or retrieved objects to reduce the overall response time to users. The resulting performance gain can mean the difference between a successful application and a slow application that frustrates its user base. So, then, how do we handle caching in the J2EE-based ICBB application?

Page caching: Unlike .Net, in J2EE caching generated HTML does not typically fall under the J2EE developer/administrator’s control. Rather, the JSP/servlet container controls page caching under the covers as it sees fit. That lets JSP developers focus on constructing the JSP without worrying about explicitly managing caching policies or enforcing them.

However, in the spirit of flexibility, an open source JSP tag library from OpenSymphony lets JSP developers control JSP caching. In addition, vendors such as BEA also support JSP caching, albeit in a proprietary fashion.

Data caching: J2EE’s data-caching strategy depends on the data access strategy in use. EJB 2.0-compliant containers provide advanced caching strategies. Vendors, moreover, compete on the strength of their implementation/interpretation of the baseline EJB 2.0 specification. With more mature J2EE offerings, developers can use transactions directly against a cache, safe in the knowledge that the cache provider ensures the database remains consistent.

Presentation tier

The ICBB presentation tier contains numerous Webpages, each comprising an ASPX page and code-behind. The ASPX page represents the UI (user interface); it contains HTML and custom tags that correspond to ASP.Net Web controls. The code-behind represents the behavior behind the UI; it contains the page class’s definition.

Create the UI by dragging ASP.Net Web controls onto ASPX pages using the Visual Studio.Net designer. After that, you code event handlers contained in the ASPX page’s code-behind. That physical separation disentangles the UI from the behavior associated with the UI, similar to how J2EE allows developers to use tag libraries to simplify JSPs.

For example, the Login page code-behind contains an event handler to handle the Login button’s click event. When the user clicks the Login button, ASP.Net calls the appropriate event handler defined in the ASPX page’s code-behind. Using such an event-driven programming model improves productivity because most developers can readily understand it.

Web controls also improve productivity by providing advanced features not found in standard HTML controls. For example, each control can automatically maintain its state from one roundtrip to another. When pages change, you don’t need to repopulate the category ListBox between requests because the ListBox Web control can maintain its state. That simplifies Web programming and improves performance by eliminating the need to reretrieve the product categories from the database.

Another important feature: You can access form data in an object-oriented way. Instead of getting form data from a key/value collection, developers access type-safe properties on Web controls declared in the ASPX page’s code-behind. For example, you can access the selected category from the ListBox control on the Product List page via ListBox.SelectedItem.Value.

Business and data tiers

As with the J2EE version, the .Net-based ICBB application relies on a single business/data tier because no significant business functionality exists beyond data access. The single tier, again like the J2EE version, contains a stateless ProductManager class responsible for retrieving, deleting, and updating products.

To retrieve products, the ProductManager’s GetProducts() method calls a stored procedure using ADO.Net classes. While GetProducts() could call inline SQL, I’ve designed it to call a stored procedure to improve performance and security.

To update a product, the ProductManager’s SaveProduct() method also calls a stored procedure to save the product updates to the database.

For transactions, recall from Part 1 that the Common Language Runtime (CLR) supports both manual and automatic transactions. Automatic transactions are easier to program, but they don’t perform as well as manual transactions.

Since the ICBB application need not support distributed transactions, I selected manual transactions. (Refer to the ProductManger.SaveProduct() method in the source code.)

Common services

Next, let’s revisit a number of bread-and-butter tasks needed in enterprise application development to see how .Net supports them:

Exception handling: In Web-based applications, users will appreciate being redirected to a user-friendly error page when they encounter an unexpected error. To accomplish that goal in the ICBB .Net application, I configured ASP.Net to redirect to a specific error page (Error.aspx, for example) when an unhandled exception throws. See the in the web.config file to see how this is done.

Logging: In .Net, .Net Framework classes Trace and Debug handle logging. With the Debug class, you can print debugging information and check program logic with assertions without affecting the shipping product’s performance or size because no executable code generates for Debug methods when doing a release-build.

To instrument release-builds, use the Trace class. Unlike the Debug class, code generates for Trace methods for debug and release-builds. In addition, you can generate trace information related to the HTTP request by adding Trace=”true” to the @Page directive (see ProductList.aspx). To view the trace output, developers use a special HTTP handler provided by ASP.Net ( http://localhost/ICBB/trace.axd).

Configuration: ASP.Net reads configuration information from the web.config XML file. If any settings within this file change, ASP.Net automatically reloads the configuration information in memory without restarting the Web server. In addition to the ASP.Net settings, you can add your own application-specific application settings in the form of key/value pairs, such as a database connection string. You can then access the configuration information using a standard API in the .Net Framework.

In the ICBB application, the ConfigurationSettings.AppSettings class reads the application’s database connection string from the web.config file.

Authentication: ASP.Net supports several authentication schemes, including Windows-, Passport-, and Forms-based, to control access to Webpages. For ICBB, I chose Forms-based authentication to avoid creating separate Windows accounts for each user and relying on Microsoft’s Passport service.

With Forms-based authentication, ASP.Net automatically redirects unauthenticated users to a custom login page. The user then provides credentials as a username and password. If the user’s credentials prove valid, ASP.Net issues an authentication cookie that allows the user to access parts of the site that require authentication. Note that ASP.Net entirely handles the redirection and cookie management. The developer merely validates the user’s credentials.

Check out the web.config file’s tag to see how I configured authentication.

Authorization: Once a user has been authenticated, you next determine what he or she is allowed to do. For example, in the ICBB application, only administrators should see the Product List page’s Edit and Delete buttons. For everyone else, those buttons should be hidden. In addition, only administrators can save products; therefore, you should restrict nonadministrators from calling the ProductManager.SaveProduct() method.

To solve the first problem, hide the Edit and Delete buttons via programmatic security checks contained in the Product List code-behind. These checks call the current principle object’s IsInRole() method. In the ICBB application, the principal represents the authenticated user logged in to the system. Solve the second problem via CLR-enforced declarative security checks. In the ICBB application, a PrincipalPermissionAttribute ensures only administrators call the ProductManager.SaveProduct() method.

Session Management: ASP.Net, like its JSP counterpart, strongly supports session state management through an intuitive API; developers access session state via a session object (for example, Session[“name”]). Similarly, ASP.Net can use cookies or URL rewriting (if cookies are unavailable) to locate the user’s session state. You can also configure ASP.Net (via the web.config file) to store session state on a separate server, eliminating the need for sticky sessions in a Web-farm scenario.

For the ICBB application, because the username appears on several pages throughout the application, session state holds the authenticated user’s name.

.Net tools

You can build a .Net application using your favorite text editor and the appropriate .Net-language compiler. I advise against that choice, however, except for the simplest applications. You’d give up many productivity-enhancing features provided by Visual Studio.Net. For example, when you drag an ASP.Net control onto a Web form, Visual Studio.Net adds the appropriate tags to the ASPX page and generates code in the corresponding code-behind for that control. When you double-click the control within the designer, Visual Studio.Net generates an event handler in the code-behind class to handle the default event (for example, the clicked event for a button). The idea is to let Visual Studio.Net take care of the plumbing while the developer focuses on the business problems.

In addition to Visual Studio.Net, a number of tools address other parts of the software development problem. Here’s a partial list:

NAnt: A free .Net build tool for compiling, packaging, and deploying .Net applications

NUnit: A free framework for writing repeatable tests in any .Net language

NDoc: A free documentation-generation tool for C# developers

Application server selection and portability

When talking about application servers, you cannot easily draw a parallel between J2EE and .Net because the lines between Web servers, application servers, and operating systems are becoming increasingly blurry. In the .Net world, no product called an application server exists. Instead, many of the enterprise services an application server provides, such as distributed transaction management and object pooling, are embedded within Windows 2000 Server.

Data validation

Validating user input is a common requirement, yet one that’s tedious to implement, especially when the validation must happen on the client using JavaScript and on the server. The task is further complicated by the difference in JavaScript support across browsers. Suddenly a seemingly trivial task has become a big headache.

Enter ASP.Net with its array of validation controls including required field, range, compare, and regular expression controls (developers can even write custom validation controls if one of the prebuilt controls does not suit their needs). Instead of writing client- and server-side validation logic for each input control, you tie one or more validation control to each input control using design-time properties. When a user submits a page, each validation control checks to see if the data its responsible for passes muster. If not, an error message displays on the Webpage. The validation controls and detects the requesting browser’s capabilities, letting you focus on the business problem rather than worry about technical details.

In the .Net-based ICBB application, validation controls validate user input on the Edit Product page (EditProduct.aspx).

Caching strategies

Recall that for Web applications, caching stores previously constructed HTML fragments or retrieved objects to reduce the overall response time to users. With that in mind, let’s examine .Net’s built-in caching support:

Page caching: Rather than recreating dynamic pages with each request, ASP.Net can cache entire pages or parts of a page, thereby increasing scalability by reducing the server load. Microsoft calls this kind of caching dynamic output caching.

Output caching works well for pages whose underlying content rarely changes or for those pages not requiring up-to-the-minute data synchronization, but what about pages whose content varies from one request to the next? For example, a search page shows a different result set based on the search criteria selected. ASP.Net solves the problem by varying the cached output by a set of parameters such as the query string. If the parameter value changes, ASP.Net caches a new copy of the output.

In the ICBB application, output caching has been enabled on the Welcome page via an @OutputCache directive included in the ASPX page. To see the output cache in action, try refreshing the Welcome page. Notice how often the timestamp on the page updates.

Data caching: In classic ASP, developers often used the Application object to cache frequently requested but infrequently changing data. That works great until the underlying data changes. The .Net Framework solves the problem by providing a Cache object that behaves much like the Application object with a few added benefits, such as the ability to remove items from the cache when some dependency changes (for example, a file on disk).

In the ICBB application, the ProductManager.GetCategories() method caches the product categories in the Cache with a timestamp dependency. The Cache object then evicts the data when the data expires. You can also evict cached data based on an update to the database.

And the winner is …

Well, there you have it. Our two-part series has culminated in the building of the same Web-based application with both J2EE and .Net technologies.

Well, the rumble didn’t turn out to be much of a rumble at all! .Net and J2EE are both here to stay. .Net will capture all current Microsoft developers, but will not receive waves of converts from the Java/J2EE community as reported elsewhere. Why not?

Because the two technology stacks serve different masters. .Net is Microsoft’s solution for the Microsoft OS and Intel platform combination and will flourish there. .Net cannot run on non-Microsoft platforms. In contrast, J2EE’s two lynchpins are open standards and cross-platform portability, enabled through the Java programming language and platform.

At any point in time, either camp can and will claim to have a better toolset, lower total ownership costs, better performance, and even better-looking developers! But those temporary circumstances will last for no more than three to six months on either side. In general, if you are investing in either J2EE or .Net right now, it’s a safe bet.

Would you recommend this article?

Share

Thanks for taking the time to let us know what you think of this article!
We'd love to hear your opinion about this or any other story you read in our publication.


Jim Love, Chief Content Officer, IT World Canada

Featured Download

Featured Articles

Cybersecurity in 2024: Priorities and challenges for Canadian organizations 

By Derek Manky As predictions for 2024 point to the continued expansion...

Survey shows generative AI is a top priority for Canadian corporate leaders.

Leaders are devoting significant budget to generative AI for 2024 Canadian corporate...

Related Tech News

Tech Jobs

Our experienced team of journalists and bloggers bring you engaging in-depth interviews, videos and content targeted to IT professionals and line-of-business executives.

Tech Companies Hiring Right Now