InfoWorld https://www.infoworld.com Technology insight for the enterprise Wed, 17 Apr 2024 09:50:16 +0000 http://backend.userland.com/rss092 Copyright (c) 2024 IDG Communications, Inc. en-US Go language evolving for future hardware, AI workloads Sat, 16 Nov 2024 00:17:59 +0000

The Go programming language having just turned 15 years old on November 10, proponents now are planning to adapt the Go language to large multicore systems, the latest vector and matrix hardware instructions, and the needs of AI workloads.

In a blog post on November 11, Austin Clements of the Go team said that, looking forward, Go would be evolved to better leverage the capabilities of current and future hardware. “In order to ensure Go continues to support high-performance, large-scale production workloads for the next 15 years, we need to adapt to large multicores, advanced instruction sets, and the growing importance of locality in increasingly non-uniform memory hierarchies,” Clements said. The Go 1.24 release will have a new map implementation that is more efficient on modern CPUs, and the Go team is prototyping new garbage collection algorithms that are designed for modern hardware. Some improvements will be in the form of APIs and tools that allow Go developers to make better use of modern hardware.

For AI, efforts are under way to make Go and AI better for each other, by enhancing Go capabilities in AI infrastructure, applications, and developer assistance. The goal is to make Go a “great” language for building production AI systems. The dependability of Go as a language for cloud infrastructure has made it a choice for LLM (large language model) infrastructure, Clements said. “For AI applications, we will continue building out first-class support for Go in popular AI SDKs, including LangChainGo and Genkit,” he said. Go developers already view the language as a good choice for running AI workloads.

Also on the roadmap are efforts to ensure that the Go standard library remains safe by default and by design. “This includes ongoing efforts to incorporate built-in, native support for FIPS-certified cryptography, so that FIPS crypto will be just a flag flip away for applications that need it,” Clements said.

In noting the 15th anniversary of Go’s initial open source release, Clements said the user base of the language has tripled in the past five years. Go ranked seventh in the November 2024 Tiobe index of programming language popularity, its highest ranking in the index ever. The most recent version, Go 1.23, was released in August, with faster PGO (profile-guided optimization) build times and the rollout of Go telemetry data.

]]>
https://www.infoworld.com/article/3607388/go-language-evolving-for-future-hardware-ai-workloads.html 3607388Artificial Intelligence, Generative AI, Google Go, Programming Languages, Software Development
JDK 24: The new features in Java 24 Fri, 15 Nov 2024 09:00:00 +0000

In the wake of Java Development Kit (JDK) 23, which arrived September 17, work now focuses on the planned successor release, JDK 24, which has ballooned to 21 proposed features. The two most recent additions proposals would improve Java’s resistance to quantum computing attacks, by providing Java implementations of a quantum-resistant module-latticed-based digital signature algorithm and a quantum-resistant module-latticed-based key encapsulation mechanism.

Previously proposed features include removing the 32-bit x86 port; synchronizing virtual threads without pinning; simple source files and instance main methods; permanently disabling the security manager; module import declarations; an experimental version of compact headers; primitive types in patterns, instanceof, and switch; linking runtime images without JMODs; the generational Shenandoah garbage collector; scoped values; a key derivation function API; removal of the non-generational mode in the Z Garbage Collector; stream gatherers; a vector API; a class-file API; warnings to prepare developers for future restrictions on the use of JNI (Java Native Interface); and a late barrier expansion for the G1 garbage collector.

JDK 24 outdoes JDK 23, which listed 12 official features.

Due March 18, 2025, JDK 24 has been designated a non-long-term support (LTS) release. Like JDK 23, JDK 24 will receive only six months of premier-level support from Oracle. Early access builds of JDK 24 can be found at jdk.java.net

The two features proposed for improving Java security through quantum-resistance include a quantum-resistant module-lattice-based key encapsulation mechanism (ML-KEM) and a quantum-resistant module-lattice-based digital signature algorithm (ML-DSA). ML-DSA would secure against future quantum computing attacks by using digital signatures to detect unauthorized modifications to data and to authenticate the identity of signatories. Key encapsulation mechanisms (KEMs) are used to secure symmetric keys over insecure communication channels using public key cryptography. Both features are designed to secure against future quantum computing attacks.

Flexible constructor bodies are in a third preview after being featured in JDK 22 and JDK 23, albeit with a different name in JDK 22, when the feature was called statements before super(…).  The feature is intended to reimagine the role of constructors in the process of object initialization, letting developers more naturally place logic that they currently must factor into auxiliary static methods, auxiliary intermediate constructors, or constructor arguments.

Ahead-of-time class loading and linking aims at improving startup times by making classes of an application instantly available in a loaded and linked state, when the HotSpot Java virtual machine starts. This would be achieved by monitoring the application during one run and storing the loaded and linked forms of all classes in a cache for use in subsequent runs.

The Windows 32-bit x86 port was deprecated for removal in JDK 21 with the intent to remove it in a future release. Plans call for removing the source code and build support for the Windows 32-bit x86 port. Goals include removing all code paths that apply only to Windows 32-bit x86, ceasing all testing and development efforts targeting the Windows 32-bit x86 platform, and simplifying the JDK’s build and test infrastructure. The proposal states that Windows 10, the last Windows operating system to support 32-bit operation, will reach its end of life in October 2025.

Synchronizing virtual threads without pinning involves improving the scalability of Java code that uses synchronized methods and statements by arranging for virtual threads that block in such constructs to release their underlying platform for use by other threads. This would eliminate almost all cases of virtual threads being pinned to platform threads, which severely restricts the number of virtual threads available to handle an application workload.

A fourth preview of simple source files and instance main methods would evolve the Java language so beginners can write their first programs without needing to understand language features designed for large programs. The feature was previously previewed in JDK 21, JDK 22, and JDK 23. The goal is to allow beginning Java programmers to write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow.

Permanently disabling the security manager involves revising the Java platform specification so developers cannot enable the security manager, while other platform classes do not refer to it. The security manager has not been the primary means of securing client-side Java code for many years, has rarely been used to secure server-side code, and has been costly to maintain, the proposal states. The security manager was deprecated for removal in Java 17.

Module import declarations, previously previewed in JDK 23, enhance the Java programming language with the ability to succinctly import all of the packages exported by a module. This simplifies the reuse of modular libraries but does not require the importing of code to be a module itself.

Compact object headers would reduce the size of object headers in the HotSpot VM from between 96 and 128 bits down to 64 bits on 64-bit architectures. The goal of the proposed feature is to reduce heap size, improve deployment density, and increase data locality.

A second preview of primitive types in patterns, instanceof, and switch in JDK 24 would enhance pattern matching by allowing primitive types in all patterns and contexts. The feature also would extend instanceof and switch to work with all primitive types. The feature\’s goals include enabling uniform data exploration by allowing type patterns for all types, whether primitive or reference; aligning types with instanceof and aligning instanceof with safe casting; and allowing pattern matching to use primitive types in both nested and top-level pattern contexts. This feature was previously previewed in JDK 23.

Other goals include providing easy-to-use constructs that eliminate the risk of losing information due to unsafe casts, following the enhancements to switch in Java 5 and Java 7, and allowing switch to process values of any primitive type.

With linking runtime images without JMODs, the plan is to reduce the size of the JDK by roughly 25% by enabling the jlink tool to create custom runtime images without JDK JMOD files. This feature must be enabled by default and some JDK vendors may choose not to enable it. Goals include allowing users to link a runtime image from modules regardless of whether those modules are standalone JMOD files, modular JAR files, or part of a runtime image linked previously. Motivating this proposal is the notion that the installed size of the JDK on the file system is important in cloud environments, where container images that include an installed JDK are automatically and frequently copied over the network from container registries. Reducing the size of the JDK would improve the efficiency of these operations.

Generational Shenandoah would enhance the garbage collector with experimental generational collection capabilities to improve sustainable throughput, load-spike resistance, and memory utilization. The main goal is to provide an experimental generational mode, without breaking non-generational Shenandoah. The generational mode is intended to become the default mode in a future release.

Scoped values enable a method to share immutable data both with its callees within a thread and with child threads. Scoped values are easier to reason about than local-thread variables. They also have lower space and time costs, particularly when used together with virtual threads and structured concurrency. The scoped values API was proposed for incubation in JDK 20, proposed for preview in JDK 21, and improved and refined for JDK 22 and JDK 23. Scoped values will be previewed in JDK 24.

With the key derivation function (KDF) API, an API would be introduced for key derivation functions, which are cryptographic algorithms for deriving additional keys from a secret key and other data. A goal of this proposal is allowing security providers to implement KDF algorithms in either Java code or native code. Another goal is enabling applications to use KDF algorithms such as the HMAC (hash message authentication code)-based extract-and-expand key derivation function (RFC 5869) and Argon2 (RFC 9106).

Removing the non-generational mode of the Z Garbage Collector (ZGC) is a proposal aimed at reducing the maintenance cost of supporting two different modes. Maintaining non-generational ZGC slows the development of new features, and generational ZGC should be a better solution for most use cases than non-generational ZGC, the proposal states. The latter eventually should be replaced with the former to reduce long-term maintenance costs. The plan calls for removing the non-generational mode by obsoleting the ZGenerational option and removing the non-generational ZGC code and its tests. The non-generational mode will expire in a future release, at which point it will not be recognized by the HotSpot JVM, which will refuse to start.

Stream gatherers would enhance the stream API to support custom intermediate operations. Stream gatherers allow stream pipelines to transform data in ways that are not easily achievable with the existing built-in intermediate operations. This feature was proposed as a preview in JDK 22 and JDK 23. The API would be finalized in JDK 24. Goals include making stream pipelines more flexible and expressive and allowing custom intermediate operations to manipulate streams of infinite size.

The vector API is designed to express vector communications that reliably compile at runtime to optimal vector instructions on supported CPU architectures, thus achieving performance superior to equivalent scalar computations. The vector API previously was incubated in JDK 16 through JDK 23. It would be re-incubated in JDK 24 with no API changes and no substantial implementations relative to JDK 23. Goals of the proposal include clearly and concisely expressing a wide range of vector computations in an API that is platform-agnostic, that offers reliable runtime compilation and performance on x64 and AArch54 architectures, that degrades gracefully and still functions when a vector computation cannot be expressed at runtime, and that aligns with Project Valhalla, leveraging enhancements to the Java object model.

The class-file API, previously previewed in JDK 22 and JDK 23, would be finalized in JDK 24, with minor changes. This API provides a standard API for parsing, generating, and transforming Java class files. It aims to provide an API for processing class files that tracks the class file format defined by the Java Virtual Machine specification. A second goal is to enable JDK components to migrate to the standard API, and eventually remove the JDK’s internal copy of the third-party ASM libraryChanges since the second preview include a renaming of enum values, removal of some fields, the addition of methods and method overloads, methods renamed, and removal of interfaces and methods deemed unnecessary.

Late barrier expansion for the G1 garbage collector is intended to simplify the implementation of G1’s barriers. The G1 garbage collector’s barriers record information about application memory accesses, by shifting their expansion from early in the C2 compilation pipeline to later. Goals include reducing the execution time of C2 compilation when using the G1 collector, making G1 barriers comprehensible to HotSpot developers who lack a deep understanding of C2, and guaranteeing that C2 preserves invariants about the relative ordering of memory accesses, safepoints, and barriers. A fourth feature is preserving the quality of C2-generated JIT (just-in-time)-compiled code, in terms of speed and size.

The first JDK 24-targeted feature, officially called “Prepare to Restrict the Use of JNI,” calls for issuing warnings about uses of JNI and adjusting the foreign function and memory (FFM) API, featured in JDK 22, to issue warnings in a consistent manner. These warnings are intended to prepare for a future release that ensures integrity by default by uniformly restricting JNI and the FFM API. Goals of the plan include preserving JNI as a standard way to interoperate with native code, preparing the Java ecosystem for future releases that disallow interoperation with native code by default, and aligning the use of JNI and the FFM API so library maintainers can migrate from one to the other without requiring developers to change command-line options.

Additional features targeting JDK 24 will be determined during the next several weeks. Other potential Java 24 features include structured concurrency, which simplify concurrent programming, and string templates, a feature previewed in JDK 21 and JDK 22 but dropped from JDK 23.

The most recent LTS release, JDK 21, arrived in September 2023 and is due to get at least five years of Premier support from Oracle. The next LTS version, JDK 25, is due in September 2025. LTS releases have dominated Java adoption, which means adoption of JDK 23 and JDK 24 could be on the low end as users await JDK 25.

]]>
https://www.infoworld.com/article/3491404/jdk-24-the-new-features-in-java-24.html 3491404Java, Programming Languages, Software Development
And the #1 Python IDE is . . . Fri, 15 Nov 2024 09:00:00 +0000

This half-month in Python and elsewhere: Take a peek at seven libraries for parallel processing in Python, tour Python’s most popular ORM libraries, and check out our Flask 3.0 tutorial. Also, place your bets for which contender remains standing when PyCharm, VS Code, and five other popular Python IDEs duke it out.

Top picks for Python readers on InfoWorld

The best Python libraries for parallel processing
Here are 7 frameworks you can use to spread an existing Python application and its workload across multiple cores, multiple machines, or both—and do it at scale!

Get started with Flask 3.0
Want to get started with the popular, powerful, and straightforward Flask 3.0 framework for Python? Take your first steps with this guide.

The best ORMs for data-powered Python apps
Never write raw SQL queries again! These 6 ORMs let you manage and query database objects like any other Python object.

Review: 7 Python IDEs compared
We put VS Code, PyCharm, Spyder, and four other popular Python IDEs in the ring. Which one do you think came out on top?

More good reads and Python updates elsewhere

Pyloid: A web-based GUI framework for Python
Want to create apps in the Electron or Tauri way, but with Python as your back end? Pyloid is your friend.

PEP 750—Template Strings
Check out the new Python draft proposal for a string templating system even more powerful than f-strings. Is it a valuable addition, or ultimately redundant?

Is async Django ready for prime time?
One company’s experience deploying Django in production with asynchronous code. What flaming hoops did they jump and was it worth it?

The Mill build tool needs Python support—and there’s a reward!
Up to $4,000 (US) awaits those who create Python support for this build-tool project, which already services Java, Scala, and Kotlin.

]]>
https://www.infoworld.com/article/3606874/the-1-python-ide-is.html 3606874Programming Languages, Python, Software Development
Strategies to navigate the pitfalls of cloud costs Fri, 15 Nov 2024 09:00:00 +0000

In my line of work, I often hear CIOs and CFOs say, “Cloud providers are bleeding us dry.” As ever-increasing cloud bills roll in, they’re demanding answers about what they’re paying for and why they’re paying so much.

Public cloud providers are eager to oppose this line of questioning. They point to the shared responsibility model. If cloud customers spend too much money, it’s usually because they created cost-ineffective deployments. It’s common knowledge that many enterprises “lifted and shifted” their way to the clouds with little thought about how inefficient those systems would be in the new infrastructure.

Think of it this way: If a customer puts rubber tires on a horse-and-buggy delivery cart so it can be operated on a modern highway, isn’t the cart owner responsible for its lack of speed and increased operating expenses, and not the highway department? Yes, but the situation is not completely one-sided, and the cloud providers are not blameless. Let’s look at what they are doing wrong.

Complex pricing models

Purposely or not, public cloud providers created intricate pricing structures that are nearly incomprehensible to anyone who does not spend each day creating cloud pricing structures to cover every possible use. As a result, enterprises often face unexpected expenses. Many of my clients frequently complain that they have no idea how to manage their cloud bills because they don’t know what they’re paying for.

The solution to this problem is straightforward. Until providers simplify their pricing models, enterprises should assign a specific employee to be the pricing structure expert. That person can engage with cloud advisors and use cost calculators and other tools to help illuminate the intricacies of pricing models. Another option is consulting services that specialize in cloud economics.

However, many enterprises are pushing back on the notion that they need to spend even more money to figure out how they spent too much in the first place. Cloud providers need to do a much better job of making their pricing easier to understand. If you provide pertinent facts and information to your clients, you empower them to make changes that will benefit everyone. For example, let’s say the highway department knows that a motorized delivery van is 8.5 times more efficient than a horse-drawn delivery cart. The horse’s owner now has solid facts; replacement will result in a fully realized ROI in 1.25 years. Getting the horse and buggy off the roads will also make road management and maintenance tasks easier for the highway department. Everyone wins.

Overprovisioning and underutilization

Cloud providers often encourage enterprises to overprovision resources “just in case.” Enterprises still pay for that unused capacity, so the misalignment dramatically elevates costs without adding business value. When I ask my clients why they provision so much more storage or computing resources beyond what their workload requires, the most common answer is, “My cloud provider told me to.” Again, there’s an easy answer. Enterprises should adopt regular monitoring strategies to align resource allocation with usage demands.

Better cost management tools

Many providers offer cost management tools, but they are too complex or insufficient for effective tracking. Some enterprises may try other third-party tools to manage costs, but most enterprises just keep paying whatever providers ask.

The answer for this one is not so easy. Enterprises need to adopt regular monitoring strategies to align resource allocation with usage demands. They can also mitigate unnecessary spending by implementing rightsizing tactics and deploying tools to track and optimize cloud use. Sadly the state of the tools and the knowledge to construct monitoring strategies is pretty lacking right now.

For enterprises, these tools are essential. Companies should fully utilize the available features in cost management dashboards to gain insight into their spending. Establishing spending alerts and conducting periodic reviews of cost reports can improve financial oversight and compliance with budgetary constraints.

Cloud providers also need to do better. Instead of pushing back on enterprises that are having issues, help them. Now there’s a new concept that could help both sides.

Automatic scaling without proper governance

One of the best features of public cloud computing is autoscaling so you’ll never run out of resources or suffer from bad performance due to insufficient resource provisioning. However, autoscaling often leads to colossal cloud bills because it often is triggered without good governance or purpose.

Here’s a simple solution, although most enterprises don’t understand it: Set clear guidelines and thresholds for scaling operations. This avoids the financial impact of unchecked scaling by continuously reviewing and adjusting policies to align with evolving business needs and budget capabilities. The parameters need to be paired with sound cost governance systems. However, the cloud providers’ systems are often insufficient, and other paths should be found.

Lack of transparency in service offerings

Unclear service offerings and related charges can lead to unpleasant billing surprises. Having a thorough understanding of the utilized services is essential. Organizations should prioritize regular training for IT teams to ensure they comprehensively understand the cost implications of various cloud services. Developing a full grasp of the service terms and conditions will further inform decisions. This is another area where, once again, the cloud providers need to improve transparency.

Addressing these cost pitfalls requires a strategic approach to cloud management, which many enterprises avoid, and most cloud providers do not promote. By implementing informed and proactive strategies to tackle complex pricing, optimize resource usage, improve cost management, control scaling, and improve service transparency, enterprises can significantly reduce wasteful spending and maximize the value of their public cloud investments.

A day of reckoning is on the horizon. Currently, most enterprises blindly pay these inflated bills, albeit with many complaints. Enterprises, you need to fix the problems you are responsible for fixing. Cloud providers, you need to become a true partner. Help your customers use your resources in the most business-efficient ways possible. In the long run, helping them will help you.

]]>
https://www.infoworld.com/article/3606881/strategies-to-navigate-the-pitfalls-of-cloud-costs.html 3606881Cloud Architecture, Cloud Computing, Cloud Management
Rust Foundation moves forward on C++ and Rust interoperability Thu, 14 Nov 2024 21:18:30 +0000

The Rust Foundation, which stewards development of the Rust language, has released a statement addressing challenges and opportunities for interoperability between Rust and C++, with the intent of making cross-language development more accessible and approachable.

Formally announced November 12, the foundation’s C++/Rust Interoperability Problem Statement aims to overcome the obstacles to Rust-C++ interoperability. While C interoperability has been a focus of Rust, various factors have inhibited a mature, standard, and automatic solution for developing software using C++ and Rust together, the document states. To overcome these obstacles, the initiative will pursue a top-down, problem-space approach to enable cooperation and consensus among stakeholders including the Rust project, Rust Foundation member organizations, and individuals and organizations using C++ or Rust. The core challenge is in developing a mature, standardized approach to C++ and Rust interoperability, despite Rust’s historical focus on C compatibility.

Material resources contributed to the initiative will be used to pursue three concurrent strategies:

  1. Improve existing tools and address tactical issues within the Rust Project to reduce interoperability friction and risk, in the short term.
  2. Build consensus around long-term goals requiring changes to Rust itself and develop the tactical approaches to begin pursuing them.
  3. Engage with the C++ community and committee to improve the quality of interoperation for both languages, to help realize mutual goals of safety and performance.

C++ and Rust interoperability, according to the statement, is the ability to exchange data and execute code written in both languages. “Both C++ and Rust will play important roles in systems programming for the foreseeable future,” the statement reads. “With such a high degree of overlap in applicability, using both languages together is essential to pursuing safety and performance which is maintainable and scalable.” Empowering technologists to choose the language best suited to their situation and minimizing costs and risks of interoperation is the core goal of the initiative.

The C++ and Rust interoperability initiative was launched in February 2024 with a $1 million contribution from Google.

]]>
https://www.infoworld.com/article/3606753/rust-foundation-moves-forward-on-c-and-rust-interoperability.html 3606753C++, Programming Languages, Rust, Software Development
JetBrains IDEs ease debugging for Kubernetes apps Thu, 14 Nov 2024 20:06:06 +0000

JetBrains IDEs, with new 2024.3 edition releases, now provide a logical code structure view alongside the familiar physical code structure view in the Structure tool window. The updated IDEs also streamline debugging for Kubernetes applications and provide cluster-wide Kubernetes log access with streaming and pattern matching.

JetBrains announced the 2024.3 releases on November  12. The updated versions of the IDEs will be available soon through JetBrains’ website and Toolbox App, the company said.

The JetBrains IDEs covered by the release include IntelliJ IDEA ( Java and Kotlin), PyCharm (Python), WebStorm (JavaScript and TypeScript), GoLand (Go), and RubyMine (Ruby). Also released was JetBrains AI Assistant 2024.3, which now allows users to choose between between Google Gemini, OpenAI, or local large language models for code chat. This update also brings advanced code completion for all major programming languages, JetBrains said.

Specific JetBrains 2024.3 updates include the following:

  • IntelliJ IDEA lets developers work more efficiently with updates, offering capabilities such as better handling of aliases in the data flow engine for Java and Kotlin. Also featured is a code formatter to preserve blank lines for clearer code.
  • JetBrains AI Assistant adds Google Gemini models including Gemini 1.5 Pro 002 and Flash 002 to the model lineup. Developers can choose between Gemini, OpenAI, or local models to tailor their AI chat experience.
  • PyCharm brings AI to the editor. Users can type a natural language request in a new line in the editor and the IDE will respond with a suggestion. Code assistance is provided for Python, JavaScript, TypeScript, JSON, and YAML.
  • WebStorm offers an enhanced framework component navigation and renaming, database tools, SQL support, and improved AI-driven code completion.
  • GoLand has a set of features and inspections to streamline developer workflow. AI users can benefit from refined multi-line completion and inline prompts. The latest Go language features are supported.
  • CLion, for C and C++, offers new capabilities for embedded development, such as debug servers and support for native ZephyrWest debugging, and an ability to attach the debugger to an unstarted process.
  • Rider, for .NET and games development, brings support for the .NET 9 SDK including the latest C# 13 features.
  • PhpStorm, for PHP, has new inspections and quick fixes to help developers upgrade to PHP 8.4. Parallel and mutation testing in the Pest testing framework is supported.
  • RubyMine introduces Rails 8 support, including Kamal 2 code completion and code insight for Solid Queue and Solid Cache.
  • ReSharper, a Visual Studio extension for .NET developers, offers support for the latest C# 13 features.

]]>
https://www.infoworld.com/article/3606613/jetbrains-ides-ease-debugging-for-kubernetes-apps.html 3606613Development Tools, Integrated Development Environments, Java, Python, Software Development
How to use DispatchProxy for AOP in .NET Core Thu, 14 Nov 2024 09:00:00 +0000

Aspect-oriented programming (AOP) decomposes an application’s source code into distinct aspects that isolate the core business logic from cross-cutting concerns. With AOP, cross-cutting concerns like logging and authentication become “aspects” that you program in one place and then apply in all of the places they’re needed. Thus AOP enhances modularity, makes your code more readable and maintainable, and helps you reduce coding errors. You can learn more about AOP from my previous article here.

We’ve examined how we can implement AOP in C# using PostSharp and Autofac. In this article, we’ll look at implementing AOP in C# using the DispatchProxy class. To work with the code examples provided in this article, you should have Visual Studio 2022 Preview installed in your system. If you don’t already have a copy, you can download Visual Studio 2022 Preview here.

Create a console application project in Visual Studio 2022 Preview

First off, let’s create a .NET Core 9 console application project in Visual Studio 2022 Preview. Assuming you have Visual Studio 2022 Preview installed, follow the steps outlined below to create a new .NET Core 9 console application project.

  1. Launch the Visual Studio IDE.
  2. Click on “Create new project.”
  3. In the “Create new project” window, select “Console App (.NET Core)” from the list of templates displayed.
  4. Click Next.
  5. In the “Configure your new project” window, specify the name and location for the new project.
  6. Click Next.
  7. In the “Additional information” window shown next, choose “.NET 9.0 (Preview)” as the framework version you would like to use.
  8. Click Create.

We’ll use this .NET 9 console application project in the subsequent sections of this article.

The perils of cross-cutting concerns

Cross-cutting concerns are application concerns that span several modules or layers of an application. Typical examples include logging, authentication, caching, performance monitoring, and transaction management. These concerns add a degree of complexity to the application’s core business logic.

Aspect-oriented programming is a proven approach to addressing these challenges. By modularizing these concerns, AOP decreases code clutter and improves code readability and maintainability, thereby enabling your application’s source code to be flexible.

The DispatchProxy class in C#

The most commonly used technique for implementing aspect-oriented programming is to intercept method calls in AOP, using a dynamic proxy for code interception. The DispatchProxy class provides a way to create proxy objects in C# and intercept method calls. This feature helps implement aspects without polluting or complicating an application’s business logic with cross-cutting concerns.

Essentially, DispatchProxy is an abstract class pertaining to the System.Reflection namespace. It contains the declaration of only two methods, an abstract method named Create and a generic method named Invoke as shown below.


protected abstract object Invoke(MethodInfo targetMethod, object[] args);
public static T Create() where TProxy : DispatchProxy

Using the DispatchProxy class in C#

Consider the following code that contains an interface and a class that implements the interface.


interface IMyInterface
{
    void Display(string text);
}
class MyClass : IMyInterface
{
    public void Display(string text)
    {
        Console.WriteLine(text);
    }
}

Create another class named MyClassDispatchProxy that extends the DispatchProxy class and implements the IMyInterface interface. We’ll use this class to create proxy object shortly.


class MyClassDispatchProxy : DispatchProxy where T : class, IMyInterface
{
    private IMyInterface Target { get; set; }
    protected override object Invoke
    (MethodInfo targetMethod, object[] args)
    {
        return targetMethod.Invoke(Target, args);
    }
    public static T CreateProxy(T target)
    {
        var proxy = Create>() as MyClassDispatchProxy;
        proxy.Target = target;
        return proxy as T;
    }
}

You can use the following piece of code to invoke the Display method using the proxy instance.


IMyInterface decoratedObject = MyClassDispatchProxy.CreateProxy(new MyClass());
decoratedObject.Display("This is a text message for testing purposes only.");

When you call the CreateProxy method, it calls the Create method of the abstract base class to create a proxy object for you. When you call any method on the proxy instance called IMyInterface, the proxy will automatically call the Invoke() method.

Use DispatchProxy to add logging capabilities

Let us now update the MyClassDispatchProxy class to include logging capabilities and change its name to CustomLogger. To do this, create a new C# class named CustomLogger that extends the DispatchProxy class.


public class CustomLogger : DispatchProxy where T : class
{
    private readonly ILogger _logger;
    private T target;
    protected override object Invoke
    (MethodInfo targetMethod, object[] args)
    {
       throw new NotImplementedException();
    }
    public static T Create(T target)
    {
       throw new NotImplementedException();
    }
}

The CustomLogger class shown in the preceding code uses Serilog to log data in this example. The following code snippet shows how you can update the Invoke method we created in the MyClassDispatchProxy class earlier to incorporate logging capabilities.


protected override object Invoke
    (MethodInfo targetMethod, object[] args)
    {
        if(targetMethod == null)
            throw new ArgumentNullException(nameof(targetMethod));
        _logger.Information($"Entering method: {targetMethod.Name}...");
         var result = targetMethod.Invoke(target, args);
        _logger.Information($"Exiting method: {targetMethod.Name}...");
        return result;
    }

Note how the method calls are logged before and after invocation in the Invoke method. If the targetMethod instance is null, the Invoke method throws an exception. In the Create method, we create a new instance of the CustomLogger class and then set the target object based on which the proxy object will intercept method calls.

Complete source code for DispatchProxy logging example

The complete source code of the CustomLogger example is given below for your reference.


public class CustomLogger : DispatchProxy where T : class
{
    private readonly ILogger _logger;
    private T target;
    public CustomLogger()
    {
        _logger = new LoggerConfiguration()
        .WriteTo.Console()
        .CreateLogger();
    }
    protected override object Invoke
    (MethodInfo targetMethod, object[] args)
    {
        if(targetMethod == null)
            throw new ArgumentNullException(nameof(targetMethod));
        _logger.Information($"Entering method: {targetMethod.Name}...");
         var result = targetMethod.Invoke(target, args);
        _logger.Information($"Exiting method: {targetMethod.Name}...");
        return result;
    }
    public static T Create(T target)
    {
        var proxy = Create>() as CustomLogger;
        proxy.target = target;
        return proxy as T;
    }
}

Run the application

Finally, create an instance of type IMyInterface that you would want to create a proxy object for and pass it to the Create method of the CustomLogger class as shown in the code below.


var myObject = new MyClass();
var proxy = CustomLogger.Create(myObject);
proxy.Display("Test message");

When you run the above piece of code, you’ll be able to see the text messages displayed before and after the method invocation as shown in Figure 1.

DispatchProxy example

Figure 1. DispatchProxy in action!

IDG

DispatchProxy proxies interfaces, not classes

The DispatchProxy class in C# enables you to intercept method calls and modify method invocations at runtime by using reflection. It is an excellent choice in applications where interface-based programming is used. Moreover, because the DispatchProxy class is available as part of the .NET Core library, you do not need to use any third-party libraries to implement aspect-oriented programming.

However, remember that DispatchProxy works only with interfaces, i.e., it proxies interfaces, not classes. You should also be aware of the potential performance implications (and be prepared to address any performance challenges) that might creep in because of the dynamic nature of proxy creation when working with DispatchProxy.

]]>
https://www.infoworld.com/article/3595609/how-to-use-dispatchproxy-for-aop-in-net-core.html 3595609C#, Development Libraries and Frameworks, Microsoft .NET, Software Development
Understanding Hyperlight, Microsoft’s minimal VM manager Thu, 14 Nov 2024 09:00:00 +0000

Virtualization seemed to be one of those technologies that was done. With Hyper-V, VMware, and KVM all offering similar features and performance, all that was left to do was to support new chipset instructions and fix bugs. But slowly things began to change, as operating systems and platforms adopted virtual machines and containers as key building blocks.

Windows support for virtualization-based security was one key driver, with new paravisor-based features in Hyper-V’s Krypton binding platform and virtual machines together so that users didn’t know that they were using code running in a VM. Security has driven many other recent virtualization developments, with tools like OpenHCL providing a framework for a virtualization-based trusted execution environment.

Modern virtual machines for serverless computing

There’s another increasingly important place where VMs are important. In the cloud-native and serverless computing world, we need to be able to launch code fast to scale with demand and support scaling down to zero when necessary. This is how we run data centers economically, ensuring we don’t need to keep loads running in case a user needs them.

We need to be able to launch small elements of functionality in microseconds, fast enough that users don’t notice any latency. This requires a new form of virtualization, where the hypervisor provides the APIs that would traditionally have been hosted by a guest OS, providing a lightweight set of services that can be accessed through known interfaces.

Introducing Hyperlight: a small, fast VM manager

In 2023 Azure CTO Mark Russinovich mentioned some work being done within Azure on a virtual machine manager designed for use with WASI, the Web Assembly System Interface. Hyperlight would work by eliminating the requirement to have a guest OS in a virtual machine, instead simply exposing a virtual CPU and I/O to guest applications. The resulting minimalist approach was showing good results and allowed either statically linked binaries to boot and run.

Hyperlight is now a public project with a GitHub repository. It’s still very much experimental, but there’s enough to explore what you can do with your own minimal VMs, especially how you can write code for them. Microsoft suggests that Hyperlight is intended for functions as a service where event-driven applications need to scale quickly, but there are other possibilities: for example, microservices in a Kubernetes environment that’s managed using Kubernetes Event-Driven Autoscaling (KEDA), or portable code for edge IoT hardware.

It’s interesting to look at other recent Azure announcements, as many of them could work well with Hyperlight, especially where both latency and density are key. Running Hyperlight on Cobalt Arm hardware would allow Azure to take advantage of its new lower power compute, and it would also allow Drasi workloads to quickly respond to change notifications across many data sources.

Using Hyperlight for functions as a service

So how does Hyperlight work? To start with, all your code needs to run on the Hyperlight virtual CPU. That requires code to be compiled for it, with a set of specialized libraries to provide platform support that needs to be statically linked when compiled. This is currently available as C, though there are plans to also implement it in Rust. That approach makes using a Web Assembly runtime a good choice, as it allows you to build the runtime once and then use WASI to run arbitrary code written in a higher-level language and compiled to Web Assembly’s wasm instruction set. That should allow you to use any language that has a wasm compiler, including .NET languages such as C#.

Hyperlight provides the basic infrastructure for running a thinly provisioned VM. This sets up the necessary memory via the host OS hypervisor APIs, enabling the virtual CPU and its registers, before running a pre-configured app at a set instruction pointer. It’s an approach that’s optimized for running one process per VM, with the app and VM bundled together.

While that may seem like other virtual machine managers, it’s very much optimized for fast cold starts, going from nothing to a fully instantiated application in the minimum possible time. By launching functions quickly, Hyperlight allows Azure to scale its functions-as-a-service tool more effectively by shutting them down completely when not running, ensuring that when a function is active, it’s computing, not simply using power while waiting to be called.

Launching a Hyperlight-hosted VM takes a couple of milliseconds, as opposed to 120 or so for a traditional VM. It’s slower than launching a web assembly runtime on its own, but using a VM provides the added level of security and isolation that’s necessary for multitenant applications.

Developing for and with Hyperlight

Hyperlight is invoked programmatically. Microsoft’s sample code is written in Rust and it takes a handful of lines of code to create a Hyperlight sandbox and load code into it. One useful option is creating a snapshot of the VM once it’s been created, which can be used to launch future instances more quickly.

Once a VM is up and running, you can use the Hyperlight Rust libraries to call a VM-hosted function directly. Your host code needs to run in a loop until the VM function halts successfully or it fails with a known or unknown error. If the function succeeds, the host passes the result on to the calling function. If it fails, it logs the appropriate error message.

Using Rust here makes sense. It’s memory-safe, so it reduces the risk of memory leaks and buffer escapes, helping keep both host and guest code secure. This is essential in a cloud-native environment where function instances are created and destroyed and there is no link between any one instance and the next.

How can you build a guest binary for use in Hyperlight? You need to use the Hyperlight library, with both C and Rust versions available. It’s also important to remember that this is the only one you can use, so don’t start with the standard library, even if that’s what you’ve always worked with in the past. There are other important prerequisites, including a specific entry point for your code, to trap unregistered function calls from the host.

One key point is that there is no access to the host system from the guest application unless it’s explicitly enabled by the host. Even if you have enabled that option, guest applications are strictly limited in what can be delivered, locking down both argument length and type. If what’s sent is not what’s expected, the call will be rejected by the Hyperlight host.

Security is important when building a Hyperlight host. Microsoft has put out a list of requirements that help define the host’s role as a tool for managing guest code. These include ensuring that your host doesn’t do things like create or work with files, access network resources, or even work with encryption tools. When you consider that a host may be loading more than one different function for different owners, these rules begin to make sense. There is no need to expose state or services that can be accessed by malicious actors. And if you are running a public service, you can be sure that they will be trying to do just that.

Designing for cloud economics

It’s still early days for Hyperlight, but there’s a lot to like in what we’ve been shown so far. The idea of a lightweight host for functions is a good one, especially one with the ability to truly scale to zero. As it rolls out in Azure and other cloud platforms, it should have an interesting effect on the economics of cloud-native serverless development, both for users and the cloud providers.

Scaling to zero with minimal startup latency will ensure there are no costs associated with idle functions, and at the same time, will improve overall utilization in data centers. That should be a win for everyone. Now all we need is a Hyperlight Functions runtime, one that hides the plumbing underneath Web Assembly and lets us build code in our language of choice. And that’s what handing the project over to the Cloud Native Computing Foundation should do, encouraging developers to think about how to build using Hyperlight with Kubernetes and Web Assembly.

]]>
https://www.infoworld.com/article/3604741/understanding-hyperlight-microsofts-minimal-vm-manager.html 3604741Cloud Computing, Development Tools, Microsoft Azure, Rust, Serverless Computing
TypeScript 5.7 improves error reporting Wed, 13 Nov 2024 19:32:43 +0000

TypeScript 5.7, the latest planned release of Microsoft’s JavaScript variant with syntax for types, has moved to the release candidate stage. With version 5.7, the language’s type system is now able to report errors when variables have never been initialized.

The release candidate was introduced November  8 following an October 9 beta. It can be accessed through NPM using the command: npm install -D typescript@rc.

With checks for never-initialized variables, the TypeScript team has addressed a situation where TypeScript’s checks for non-initialized variables did not always work. For example, if the not-yet-initialized variable was accessed in a separate function, the type system did not know when the function would be called; it would instead take an optimistic view that the variable would be initialized. While TypeScript 5.7 remains lenient on variables that may have been initialized, the type system now can report errors when variables were never initialized at all.

Also in TypeScript 5.7 is a new compiler option, --rewriteRelativeImportExtensions. When an import path is relative and ends with a TypeScript extension (.ts, .tsx, .mts, .cts), and it is a non-declaration file, the compiler will rewrite the path to the corresponding JavaScript extension (.js, .jsx, .mjs, .cjs). This allows for writing TypeScript code that can be run in place and be compiled into JavaScript code when ready.

TypeScript 5.7 comes on the heels of the September release of TypeScript 5.6, with capabilities including disallowing nullish and truthy checks on syntax that never varies on nullishness or truthiness.

 Other features in TypeScript 5.7 include the following:

  • TypeScript 5.7 supports --target es2024, which allows developers to target ECMAScript 2024 runtimes.
  • TypeScript 5.7 supports V8 compile caching in Node.js.
  • TypeScript now has a more consistent behavior for methods in classes when these are declared with non-literal computed property names.
  • When a function expression is contextually typed by a signature returning a generic type, TypeScript now appropriately provides an implicit any error under noImplicitAny but outside of strictNullChecks.
  • When a TypeScript file is loaded in an editor using TSServer (like Visual Studio or Visual Studio Code), the editor will try to find the relevant tsconfig.json file that “owns” the file.
  • When importing from a .json file under --module nodenext, TypeScript will now enforce certain rules to prevent runtime errors.
]]>
https://www.infoworld.com/article/3557641/typescript-5-7-improves-error-reporting.html 3557641JavaScript, Programming Languages, Software Development, Typescript
Docker tutorial: Get started with Docker volumes Wed, 13 Nov 2024 09:00:00 +0000

Docker containers are meant to be immutable, meaning the code and data they hold never change. Immutability is useful when you want to be sure the code running in production is the same as the code that passed QA testing; it’s not so useful when you need to write data and persist it across application lifetimes.

Most of the time, you can address the need for data persistence by using an external database. But sometimes an application in a container just needs to use a local file system, or something that looks like a local file system.

Enter Docker volumes, Docker’s native mechanism for dealing with local storage. A Docker volume is a convenient way to allow containerized apps to write and retrieve data through a local file system or file system-like interface. But Docker volumes are not a panacea for managing state. We must use them wisely.

How Docker volumes work

Docker volumes provide a way to map a file path inside a container, called a mount point, to a file system path or file-like object outside the container. Anything written to the Docker volume will be stored externally, so it will persist across the lifetime of one or more containers. It is also possible for multiple containers to access the same volume at once (with some caveats).

Docker volumes use a volume driver to control where data is stored. One example, Blockbridge, provides direct access to iSCSI targets through the volume driver layer. A more ambitious example is REX-Ray, a storage engine that works with a variety of storage vendors and standards. REX-Ray provides connectivity via Docker’s volume plug-in system or the more general Container Storage Interface spec.

Creating Docker volumes manually

The most basic way to create a volume is to include the -v or —volume flag, mount point, and target when you start a container:


$ docker run -P —name websvc -v /websvcdata myorg/websvc python app.py

This creates an “anonymous” volume with the mount point websvcdata and with the data stored in a randomly generated directory used by the Docker process.

You can accomplish the same thing in a Dockerfile by including a VOLUME instruction that describes the location of a volume:


FROM ubuntu: latest
VOLUME /websvcdata

This would be a good way to create a quick-and-dirty dumping ground for data in the course of a given container session. But it’s not as useful for persisting state across container sessions, since the name of the volume isn’t known ahead of time and the volume can’t be reused efficiently.

Using the Docker volume API

A better solution to the problem is to use Docker’s volume API to create named volumes. Named volumes can be easily attached to one or more containers, and thus reused a good deal more easily.


$ docker volume create websvcdata

This creates a Docker volume named websvcdata. However, the Docker volume doesn’t have a mount point in a container yet, so a container wouldn’t be able to access it by default. To create a mount point, you’d launch the container with a command like this:


$ docker run -P —name websvc -v websvcdata:/websvcdata myorg/websvc python app.py

This command is the same as the previous docker run example, but instead of the volume being created with an anonymous name, it’s created with the name websvcdata on the host. You can run docker inspect on the container and read the "Mounts" section in the resulting dump to determine if the mounts are as you intended.

Note that you can’t create a named volume with a Dockerfile, because names for Docker volumes must be specified at runtime. This is intentional, since Dockerfiles cannot assume a given host and its volume paths exist—they’re meant to be run on any system with any set of volume paths. A volume specified in a Dockerfile will be created in a location that supports the persistence of the data the volume stores for the life of the container.

If you run docker volume create with flags specific to the Docker storage driver, you can dictate many options for the volume’s creation. With the local file system driver, for instance, you can describe where to place the volume, what device or file system to use (such as an NFS share or a temporary file system), and many other controls. This way, you can place the volume on the best device for the particular use case.

A useful tip: If you create a volume and bind it to a path inside the base image that already contains data, the data inside the base image will be copied to the volume at bind time. This is a handy way to pre-populate a volume with a set of data that you want to use as a starting point. (Note that cleaning up the populated volume is your responsibility.)

Sharing Docker volumes between containers

If you want more than one container to attach to the same Docker volume, all you have to do is create the volume and attach it to multiple containers:


$ docker run -ti —name instance1 -v DataVol1:/datavol1 ubuntu

$ docker run -ti —name instance2 —volumes-from DataVol1 ubuntu

$ docker run -ti —name instance3 —volumes-from DataVol1:ro ubuntu

This creates three containers, instance1 through instance3, and attaches DataVoll to each of them. The instance3 container has DataVol1 mounted as read-only, as per the :ro after the volume name.

Be warned that Docker does not automatically mediate conflicts between containers that share the same volume. That’s up to your application. (More on this below.)

Removing Docker volumes

Volumes are not automatically removed from disk when a container is removed. This is by design, because you don’t want to remove a volume that could conceivably be used by another, as-yet-unused container in the future. That means volume unmounting and on-disk cleanup are your responsibility.

Docker provides built-in tools for facilitating volume cleanup. The docker volume command has a subcommand, docker volume prune, that removes all volumes not in use by at least one container in the system. You can also modify the scope of the deletion—e.g., remove all volumes associated with a given container—by passing command-line flags.

The limits of Docker volumes

Docker volumes aren’t a cure-all for local persistence. Because of the way containers interact with local file systems, Docker volumes can create more problems than they solve.

One key limitation is that Docker does not handle file locking in volumes used by multiple containers. That becomes the responsibility of whatever application you’re using. If you’re not confident that the application in question knows how to write to a shared file system, you could end up with file corruption in that volume. One possible solution would be to use an object storage server—for instance, a project like Minio—instead of the local file system.

Another issue with Docker volumes that they can make application portability more difficult. Every machine’s storage topology is different. If you create volumes based on assumptions about where things are in the system, you may find those assumptions are not true if you try to deploy the same containers on a system you didn’t build yourself. This is less problematic if you’re using containers only on systems where you have rigorous control over the topology—e.g., an internal private cluster—but it can come back to bite you if you decide to re-architect things later.

Finally, avoid using volumes to store stateful data that is better handled through another native mechanism in Docker. Application secrets, for instance, should be handled by Docker’s own secrets system or a third-party product like HashiCorp’s Vault, and never by way of volumes or writable container image layers.

]]>
https://www.infoworld.com/article/2268611/docker-tutorial-get-started-with-docker-volumes.html 2268611Cloud Computing, Devops, Software Development
Kotlin for Java developers Wed, 13 Nov 2024 09:00:00 +0000

After Java, Kotlin is the most popular JVM language. Kotlin is an expressive, concise language with strong functional programming support. It’s especially appealing to Java developers because it is fully interoperable with Java, and the syntax is an easy transition. Let’s take a look at this dynamic programming language.

Get started with Kotlin

Kotlin is a great language for Java developers to expand into. It complements and embellishes what you already can do with Java and offers serious power from within the JVM ecosystem. Best of all, learning and using Kotlin doesn’t demand much from your already overworked brain, as switching between Java and Kotlin is fairly simple.

Like Java, Kotlin requires that you have a JDK installed. The command-line tool SDKMan makes installing and managing Kotlin simple:


$ sdk install kotlin 2.0.20
$ kotlin -version
Kotlin version 2.0.20-release-327 (JRE 23-ea+24-1995)

Once installed, you can create and run a simple Main.kt file:


// Main.kt
fun main() {
  println("Hello, InfoWorld!")
}

To compile it, enter:


$ kotlinc Main.kt

This command outputs a class file: MainKt.class, which you can run just like any other:


$ java MainKt
Hello, Kotlin!

Notice that a function with no return value, like the one above, doesn’t declare a void return value like in Java. Instead, it simply has no return modifier at all. Unlike Java, you can declare a function with the fun keyword outside of a class. In simple cases, functions lack all the trappings we’d find in Java: no package, class name, or public static void qualifiers.  Kotlin has all these capabilities, but it hides them by default, using conventions to provide a simpler syntax up front.

The basic idea in this section was to show how easy it is to write your code in Kotlin, which is like a streamlined and expanded Java, and run it within the JVM. It’s not that common to run Kotlin directly with Java tooling, but the example makes clear the relationship between Kotlin and Java. Usually, we’d run Kotlin using the kotlin runtime or a build tool like Gradle, which you’ll see in a moment.

First-class functions in Kotlin

Kotlin is a first-class functional language. It lets you pass around and return functional references from other functions, which provides enormous flexibility.

It is also often valid to write Java code right beside Kotlin:


// Main.kt
fun main() {
    System.out.println("Hello from Java, InfoWorld!");
    println("Hello, InfoWorld!")
}

On the other hand, some differences in Kotlin’s syntax make standard Java invalid. For one thing, Kotlin does not have or allow primitive types. In this respect, it is even more Java-like than Java: everything in Kotlin really is an object. There are no int, long, double, or char exceptions. (Project Valhalla is moving Java in a similar direction.)

Kotlin also makes a strong distinction between mutable and immutable variables. This is a common trend in modern languages. Any time you can live with an immutable version, you reduce the complexity of the program. In Kotlin, val means an immutable variable, while var means mutable:


val myValInt: Int = 10;
var myVarInt: Int = 10
// myValInt++; 

You may have also noticed by now that semicolons are optional in Kotlin, as they are in JavaScript. However, the common practice in Kotlin is to avoid using terminating semicolons.

Kotlin infers types like so:


val myString = "FooBar";
println("My string ${myString} is a classic.");

The above snippet also demonstrates Kotlin’s built-in String interpolation support, which has a similar syntax to many templating tools. The dollar-sign curly-brace (${}) can also contain expressions, as in: ${myString.upperCase()}. If the variable name is one without special characters, you can use a simplified form of it:


println("When in doubt, $myString.");

Beneath everything is Java’s type system, which you can access by typing:


println(myString::class.java.typeName); // Outputs “String”

Nulls

One of Kotlin’s embellishments is its more explicit handling of nulls. The NullPointerException is one of the most familiar exceptions in Java. In Kotlin, variables are non-nullable by default. The compiler will not allow you to set a null on normal variables. If you want a nullable version, you can set it up like so:


val myNullableString: String? = null

Kotlin also has the .? and :? operators to help deal with nulls. The .? is similar to JavaScript’s recently added optional chaining operator, and lets you short-circuit on null values without verbose checks:


possiblyNull.?possiblyNullMember.?anotherMember

If any of the parts are null, the whole expression returns null, without error. The nullish coalescing operator (?:—also called Elvis operator because it’s like an emoji with Elvis hair) lets you test the left side for null and return it if its non-null. Otherwise, it’ll return the right side, which may also be null:


something :? somethingElse

If something is null, you’ll get somethingElse.

Collections

Of course, you need to be able to handle collections of variables, and Kotlin has all the sets, lists, and maps you’d expect. These also allow for both mutable and immutable variants. So if you want a mutable list of strings you can enter something like:


import kotlin.collections.*;
fun main() {
    val books: MutableList = mutableListOf("Autobiography of a Yogi", "Slaughterhouse Five", "Phaedrus");
    println(books[2]);
}

Notice we imported the collections library in this snippet. Since that library exists in the Kotlin standard library, we can compile it:


$ kotlinc Main.kt

But it won’t run. Instead, we get


$ java MainKt
Exception in thread "main" java.lang.NoClassDefFoundError: kotlin/collections/CollectionsKt
        at MainKt.main(Main.kt:14)
        at MainKt.main(Main.kt)
Caused by: java.lang.ClassNotFoundException: kotlin.collections.CollectionsKt
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:528)

This is a familiar Java error telling us a class definition for CollectionsKt can’t be found. To get around the error, we need to include the standard library during runtime, like so:


$ java -cp /home/matthewcarltyson/kotlin:/home/matthewcarltyson/.sdkman/candidates/kotlin/current/lib/kotlin-stdlib.jar MainKt
Phaedrus

This command tells Java to include the kotlin-stdlib.jar (though yours might be be in a different location). Another approach is to use the kotlin runtime, which automatically includes stdlib for you:


$ kotlin MainKt

Kotlin also gives you strong functional programming support. For example, to check our books collection for a book we want, we’d enter:


println("Phaedrus" in books)  // outputs true

Also note that we can access lists just like arrays, using brackets:


println(books[2]) // outputs “Phaedrus”

Using Gradle with Kotlin

Gradle is often used as a build tool in Kotlin because you can use the Kotlin DSL instead of Groovy.

The easiest way to use Gradle and Kotlin together is to start a fresh project with Gradle init. That command launches an interactive questionnaire from the command line, shown with my answers here:


$ gradle init
Select type of project to generate:  2: application
Select implementation language: 4: Kotlin
Split functionality across multiple subprojects?:  1: no - only one application project
Select build script DSL:  2: Kotlin
Generate build using new APIs and behavior (some features may change in the next minor release)? (default: no) [yes, no]: no  
Project name (default: kotlin): kotlin
Source package (default: kotlin): com.infoworld

My selections results in a Kotlin application using Kotlin as the build script language. Now, you can run this simple program from the project root with:


$ ./gradlew run

When you run the program, you’ll get a “Hello, World” greeting. Here’s how the project is laid out:


/settings.gradle.kts - Global settings for Gradle
/app/ build.gradle.kts - The build file
/app/src/main/kotlin/com/infoworld/App.kt - The single source file

Looking at the App.kt file, you’ll see:


package com.infoworld

class App {
    val greeting: String
        get() {
            return "Hello World!"
        }
}

fun main() {
    println(App().greeting)
}

There are some features here that you have not yet seen, including the use of a package declaration (in Kotlin, the package and directory structure don’t strictly have to match).

You can also see Kotlin’s streamlined syntax for declaring a class. In Kotlin, thedefault visibility of a class is public, so App is a public class. Inside of it, there is a read-only String member called greeting (remember that val declares a read-only variable). Notice that the greeting property declares a get() function. This is what will be executed when we use the dot operator to access it, something like a streamlined getter.

Now let’s attempt something more ambitious and download the character data for Chewbacca from the Star Wars API. We can modify the App.kt file like so:


//app/src/main/kotlin/com/infoworld/App.kt 
package com.infoworld

import com.google.gson.Gson
import java.net.URL

class App {
    fun fetchAndPrintCharacterInfo(url: String) {
        val gson = Gson()
        val response = URL(url).readText()
        val character = gson.fromJson(response, StarWarsCharacter::class.java)

        println("Name: ${character.name}")
        println("Height: ${character.height}")
    }
}

data class StarWarsCharacter(
    val name: String,
    val height: String,
)

fun main() {
    val chewbaccaUrl = "https://swapi.dev/api/people/13/"
    val app = App()
    app.fetchAndPrintCharacterInfo(chewbaccaUrl)
}

This gives us a look at Kotlin’s data class, which is designed for holding information (something akin to Java’s value objects). The StarWarsCharacter class has all the standard methods like getters and setters, hashCode, toString, and equals. It is ideal for unpacking API data into a container, which is what we’re doing here.

Add the following dependency to the dependencies section of /app/build.gradle.kts:


implementation("com.google.code.gson:gson:2.9.1")

This lets us handle the JSON we’ll get back from the API. Now, if we run the app we’ll see some information about Chewbacca:


$ ./gradlew run

> Task :app:run
Name: Chewbacca
Height: 228
Hair color: null
Eye color: null

BUILD SUCCESSFUL in 2s

Conclusion

The beauty of Kotlin for Java developers is that it fits fairly easily into your existing mental model. Kotlin lets you program inside the JVM, with all its intensive optimization and vast ecosystem, but with a functional language that is in some ways “more Java than Java,” yet easy to grasp and powerful. You can also use Kotlin alongside Java, so you don’t have to choose one or the other.

There’s a lot more to Kotlin, including an extension function (which lets you add class functions without subclasses), coroutines, more functional capabilities, lack of checked exceptions, and a simplified approach to object-oriented programming. We’ll continue exploring Kotlin and its features in my next article.

]]>
https://www.infoworld.com/article/3603580/kotlin-for-java-developers.html 3603580Java, Programming Languages, Software Development
The Agile Manifesto was ahead of its time Wed, 13 Nov 2024 09:00:00 +0000

Last week I went on a short rant about scrum, and how it isn’t agile and is, well, dumb. It occurred to me that one of the obstacles to truly being agile has been the limits of software technology. The way we had to build and deliver software didn’t lend itself to flexibility. However, we are gradually moving to a new way of development that lets us be flexible and agile.

One of the reasons that everyone wants to be agile is that there was (and still is) a huge backlash against the waterfall method. The waterfall method basically went like this:

  1. Do a lot of work up front to define the requirements.
  2. Build the software.
  3. Deliver the software to the customer. 

Waterfall makes sense at first glance — find out what the customer wants and build it — but it soon became apparent that time frames were long and things changed. What the customer envisioned at the beginning didn’t match their evolving needs by the time the product was delivered. Requirements changed from when they were laid out to when the software was delivered and there was no mechanism to accommodate this.

Change was hard

A fundamental idea of the agile methodology is to alleviate this and allow for flexibility and changing requirements. The software development process should ebb and flow as features are developed and requirements change. The software should adapt quickly to these changes. That is the heart and soul of the whole Agile Manifesto.

However, when the Agile Manifesto was conceived, the state of software development and software delivery technology was not flexible enough to fulfill what the manifesto was espousing. But this has changed with the advent of the SaaS (software as a service) model.

It’s all well and good to want to maximize flexibility, but for many years, software had to be delivered all at once. Multiple features had to be coordinated to be ready for a single release date. Time had to be allocated for bug fixing. The limits of the technology forced software development teams to be disciplined, rigid, and inflexible. Delivery dates had to be met, after all.

And once the software was delivered, changing it meant delivering all over again. Updates were often a cumbersome and arduous process. A Windows program of any complexity could be difficult to install and configure. Delivering or upgrading software at a site with 200 computers running Windows could be a major challenge. Thus it was not done frequently, or at least not frequently enough. Often, customers had to wait for an official release to get a single bug fix.

But that isn’t how we deliver software now, is it? With the rise of SaaS and CI/CD (continuous integration/continuous delivery), running software is completely under our control. Even the client app that runs in a browser sits on our servers and gets sent to the client on every request. The ability to control the software at a single point means delivery of new features and bug fixes is immediate and available to all users. The notion of a single delivery date for a collection of features falls by the wayside.

The best feature

It has been said that “Shipping is the best feature of all.” Today, a SaaS application can be delivered to customers in minutes. New customers can immediately use the entire application with minimal to no configuration. By delivering the application through the browser, developers can “ship early and often.” They can add features immediately and incrementally via feature flags, and deploy bug fixes that immediately become available to every user. 

The main reason a SaaS application can be so easily and frequently delivered is because it is so easily tested. The inputs and outputs of a SaaS back end are easily definable, and thus it is a simple matter to build automated tests. In addition, a very robust suite of tests can be run in minutes, versus the days or weeks it took to properly test the new release of a desktop application.

In addition, if a deployment is found to be problematic, rolling back to a known good state can be done in seconds. New features can be deployed under a feature flag, and if one proves problematic, it can removed with a single mouse click. 

This new model has some very powerful benefits. Features can be developed and deployed incrementally. New features can be built in parallel and deployed to subsets of customers. Teams can deliver more features sooner and at higher quality, with developers able to react quickly and flexibly to any problems. No longer do you need to gather up features and bug fixes and deliver them all on a single date.

In other words, software can now truly be built in an agile fashion.

]]>
https://www.infoworld.com/article/3603707/the-agile-manifesto-was-ahead-of-its-time.html 3603707Agile Development, Application Life Cycle Management, CI/CD, SaaS, Software Development
Visual Studio 17.12 brings C++, Copilot enhancements Wed, 13 Nov 2024 09:00:00 +0000

Visual Studio 2022 17.12, the latest version of Microsoft’s signature integrated development environment (IDE), is now generally available, with improvements ranging from productivity enhancements for C++ developers to integrated AI variable inspection in the GitHub Copilot AI-powered programming assistant.

Released November 12, the same day as Microsoft’s .NET 9 application platform, Visual Studio 2022 17.12 can be downloaded from the Visual Studio website.

The updated IDE focuses on working with .NET 9 projects and AI improvements, according to Microsoft, but also has new capabilities for C++ developers. C++ developers now can set command line arguments right from the toolbar. They also can open a folder for an Unreal Engine uproject, thus getting a new way to open a uproject. Also featured is a clearer view of a file in Build Insights for C++ developers, with path adjustments. Microsoft has focused previously on C++ accommodations in Visual Studio.

With GitHub Copilot, debugging workflow is improved with integrated AI variable inspection. Developers also can fix code with Copilot, taking advantage of AI assistance to resolve code issues. Better AI completions for C# are featured as well.

To enhance debugging, the Visual Studio debugger now displays inline return values. And debugging has been improved for Blazor WebAssembly apps targeting .NET 9 or later. Among the productivity improvements, copying an error from the Error List now copies just the description, rather than entire row to the clipboard, and when Code Cleanup is run on Save, it now operates in a non-blocking manner, for a smoother coding experience. In Code Search, users now can navigate to a specific line in the current document or other specified document.

With Visual Studio 2022 17.12, the IDE now preserves font and font size preferences across a theme change. Mark of the Web (MotW) security warnings now are integrated into overall trust functionality, and Visual Studio now alerts the user if digital certificate problems are detected during network calls. For the cloud, publishing to Azure WebJobs on Linux now is supported by right-click publish capability. For the web, HTTP files now support request variables. Developers can send a request and then use data from the response, or request, in future requests.

In JavaScript and TypeScript projects, developers now can author test cases with Vitest. TypeScript 5.7, meanwhile, entered a release candidate stage on November 8, after being introduced as a beta on October 9.

]]>
https://www.infoworld.com/article/3603830/visual-studio-17-12-brings-c-copilot-enhancements.html 3603830Artificial Intelligence, C++, Generative AI, Integrated Development Environments, Microsoft .NET, Software Development, Visual Studio
Microsoft’s .NET 9 arrives, with performance, cloud, and AI boosts Tue, 12 Nov 2024 22:09:50 +0000

Microsoft has announced the general availability of .NET 9, a major upgrade of its open source software development platform that features scads of performance enhancements and new capabilities for building cloud-native and generative AI-enabled applications.

Released November 12, .NET 9 can be downloaded from dotnet.microsoft.com.

The new .NET release features more than 1,000 performance-related changes across the runtime, workloads, and languages, along with more efficient algorithms to generate better code, Microsoft said. The Server GC has been changed to be adaptive to application memory requirements as opposed to the resources (memory and CPU) available in the environment (machine, VM, or container). Also, the runtime returned to vectorization, adding support for Arm64 SVE and Intel AVX10 silicon and hardware-accelerating the runtime. Dynamic Profile Guided Optimization (PGO), meanwhile, has been updated to optimize more code patterns.

On the AI front, Microsoft has made it easier to integrate AI-infused controls into .NET apps by building out a smart components ecosystem. Also, in collaboration with Semantic Kernel, Microsoft has introduced a set of abstractions to the .NET ecosystem under Microsoft.Extensions.AI and Microsoft.Extensions.VectorData that provide a unified layer of C# abstractions for interacting with AI services, such as small and large language models (SLMs and LLMs), embeddings, vector stores, and middleware. Additionally, improvements have been made to libraries and primitive types to improve AI development.

For the .NET Aspire cloud stack, the release of .NET Aspire 9 brings features such as the ability to start and stop resources from the dashboard, keep containers alive between debug sessions, and access new APIs, including WaitFor, to better manage resource startup.

Accompanying .NET 9 are new releases of the C# and F# programming languages.

For C# 13, the focus was on features to make it easier, faster, and safer for developers to write code in preferred styles. The use of the params modifier in method signatures is boosted in C# 13 with the addition of collections expressions. Thus, developers are no longer limited to using array types with params and can use any supported collection type. C# 13 also unlocks even more high-performance code by introducing new ways to use ref struct values and makes it easier to work with multi-threaded applications with System.Threading.Lock.

F# 9 offers language, library, and tool enhancements intended to make programs safer, more resilient, and performant. Nullable reference types bring type safety to interactions with C# libraries, while optimized integral ranges speed up for loops and other comprehensions. Optimized equality checks avoid boxing and increase performance of many common operations.

The ASP.NET Core web framework in .NET 9 brings improvements to help ensure apps are secure by default. It is now easier to set up a trusted development certificate on Linux to enable HTTPS during development. The framework also features improved monitoring and tracing along with performance improvements, with higher throughput, faster startup time, and less memory usage. For static web assets, like JavaScript and CSS files, ASP.NET Core in .NET 9 now optimizes these files during build and publish for efficient deployment.

Microsoft’s Blazor web framework in .NET 9, meanwhile, features performance improvements across all areas, as well as a new solution template that makes it easier to create .NET MAUI native and Blazor web client apps that share the same UI. Further, Blazor now can detect the component render mode at runtime via the RendererInfo API and adjust component rendering.

Also in .NET 9, Windows apps will have access to the latest OS features and capabilities while ensuring they are more performant and accessible than before. New built-in support for OpenAPI document generation is offered via the Microsoft.AspNetCore.OpenAPI package. And a new template for .NET MAUI includes 14 Syncfusion controls and other popular libraries, with practices for database access, Model-View-ViewModel, navigation, and other common app patterns.

]]>
https://www.infoworld.com/article/3603700/microsofts-net-9-arrives-with-performance-cloud-and-ai-boosts.html 3603700Artificial Intelligence, C#, Development Libraries and Frameworks, Generative AI, Microsoft .NET, Software Development
Red Hat OpenShift AI unveils model registry, data drift detection Tue, 12 Nov 2024 19:47:21 +0000

Red Hat has updated Red Hat OpenShift AI, its cloud-based AI and machine learning platform, with a model registry with model versioning and tracking capabilities, data drift detection and bias detection tools, and LoRA (low-rank adaptation) fine-tuning capabilities. Stronger security also is offered, Red Hat said.

Version 2.15 of Red Hat OpenShift AI will be generally available in mid-November. Features highlighted in the release include:

  • A model registry, currently in a technology preview state, that provides a structured way to share, version, deploy, and track models, metadata, and model artifacts.
  • Data drift detection, to monitor changes in input data distributions for deployed ML models. This capability allows data scientists to detect when the live data used for model interference significantly deviates from the data upon which the model was trained. Drift detection helps verify model reliability.
  • Bias detection tools to help data scientists and AI engineers monitor whether models are fair and unbiased. These predictive tools, from the TrustyAI open source community, also monitor models for fairness during real world deployments.
  • Fine-tuning with with LoRA, to enable more efficient fine-tuning of LLMs (large language models) such as Llama 3. Organizations thus can scale AI workloads while reducing costs and resource consumption.
  • Support for Nvidia NIM, a set of interface microservices to accelerate the delivery of generative AI applications.
  • Support for AMD GPUs and access to an AMD ROCm workbench image for using AMD GPUs for model development.

Red Hat OpenShift AI also adds capabilities for serving generative AI models, including the vLLM serving runtime for KServe, a Kubernetes-based model inference platform. Also added is support for KServe Modelcars, which add Open Container Initiative (OCI) repositories as an option for storing and accessing model versions. Additionally, private/public route selection for endpoints in KServe enables organizations to enhance the security posture of a model by directing it specifically to internal endpoints when needed.

Red Hat OpenShift AI 2.15 also adds predictive and generative AI enhancements to data science pipelines and experiment tracking, so data scientists can more easily manage and analyze pipeline runs grouped in a logical structure. And it adds hyperparameter tuning with Ray Tune, providing advanced optimization algorithms to improve accuracy and train models more efficiently.

]]>
https://www.infoworld.com/article/3603517/red-hat-openshift-ai-unveils-model-registry-data-drift-detection.html 3603517Artificial Intelligence, Cloud Computing, Generative AI, PaaS, Software Development
Go language rises in Tiobe popularity index Tue, 12 Nov 2024 19:09:05 +0000

The Google-built Go language has reached an all time high position in the Tiobe index of programming language popularity, ranking seventh in the November 2024 edition of the index.

While Go already had cracked Tiobe’s top 10, the language had never ranked higher than eighth. “What makes Go unique in the top 10 is that Go programs are fast and easy to deploy while the language is easy to learn,” said Paul Jansen, CEO of software quality services vendor Tiobe. Although the Python language is similarly easy to learn, it is not fast, and deployment for larger Python programs is fragile due to dependencies on all kinds of versioned libraries in the environment, Jansen said. And if compared to the Rust language, Go is a bit slower, but Go programs are much easier to understand, he added. Rust ranks 14th in this month’s index while Python is first overall.

The next hurdle for Go is to surpass JavaScript, which is currently ranked sixth. While JavaScript will be a tough language to pass, considering its ubiquity in software development, Go could do so in three years if trends continue, Jansen said.

The monthly Tiobe Progamming Community Index rates languages based on the number of skilled engineers worldwide, courses, and third-party vendors pertinent to the language. Ratings are formulated based on examinations of websites such as Google, Bing, Wikipedia, Amazon, and more than 20 others.

The Tiobe index top 10 for November:

  1. Python, with a rating of 22.85%
  2. C++, 10.64%
  3. Java, 9.5%
  4. C, 9.01%
  5. C#, 4.98%
  6. JavaScript, 3.71%
  7. Go, 2.35%
  8. Fortran, 1.97%
  9. Visual Basic, 1.95%
  10. SQL, 1.94%

The rival Pypl Popularity of Programming Language Index, which also is published monthly, bases its ratings on how often language tutorials are searched on in Google. The Pypl index top 10 for November:

  1. Python, with a 29.39% share
  2. Java, 15.52%
  3. JavaScript, 8.16%
  4. C/C++, 6.9%
  5. C#, 6.48%
  6. R, 4.71%
  7. PHP. 4.09%
  8. TypeScript, 2.91%
  9. Swift, 2.64%
  10. Rust, 2.64%
]]>
https://www.infoworld.com/article/3603508/go-language-rises-in-tiobe-popularity-index.html 3603508Google Go, Programming Languages, Software Development
Red Hat Developer Hub adds AI templates Tue, 12 Nov 2024 14:00:00 +0000

Red Hat Developer Hub, an enterprise-grade internal developer portal for platform engineering teams, is adding enhancements for AI, with five templates for building AI-powered applications for common use cases.

Rolled out on November 12, the AI-focused software templates are intended to address resource constraints and skills gaps facing developers working on AI priorities. The templates leverage pre-architected and supported approaches, so developers are able to build and deploy AI-enabled services or components without having to learn all the details of the technology used to implement it, Red Hat said. 

The new templates support the following common AI use cases:

  • Audio-to-text application: An AI-enabled audio transcription application in which users can upload an audio file to be transcribed
  • Chatbot application: A chat application enabled by a large language model (LLM) that creates a bot that replies with AI-generated responses
  • Code generation application: An LLM-enabled code generation application for a specialized bot to help with code-related queries
  • Object detection application: Enables developers to upload an image to identify and locate objects in the image
  • Retrieval-augmented generation (RAG) chatbot application: Enables developers to embed files containing relevant information to allow the model to provide more accurate responses

Red Hat said Developer Hub’s software catalog allows developers and platform engineers to record and share details of their organization’s assets, LLMs, AI servers, and associated APIs.

]]>
https://www.infoworld.com/article/3601599/red-hat-developer-hub-adds-ai-templates.html 3601599Generative AI, Red Hat, Software Development
Snowflake bares its agentic AI plans by showcasing its Intelligence platform Tue, 12 Nov 2024 14:00:00 +0000

As enterprises look to automate more processes with the help of AI-based agents that don’t require human intervention, Snowflake has showcased a new offering at its ongoing developer conference, Build 2024, which it claims is its agentic AI proposition for enterprises.

Named the Snowflake Intelligence platform, the low-code offering, expected to be in private preview soon, is designed to help enterprises unlock insights from their data through the use of data agents, and to take action on these insights.

Snowflake Intelligence will allow enterprise users to create their own data agents using natural language and will address question-and-answer tasks that require structured data to begin with, according to Baris Gultekin, Head of AI at Snowflake.

“It will expand to use cases that also require the use of unstructured data currently siloed in places like Google Workspace, Confluence, Salesforce, and more. Snowflake Intelligence will also support business intelligence tasks, ranging from generating quick answers to creating interactive charts for deeper insights,” Gultekin said, adding that the goal is to start supporting use cases that leverage both structured and unstructured data.

One such example could be a user deriving insights that require using data from multiple sources such as an analytical table, a document from SharePoint, or notes from a Salesforce account.

The platform also supports API calls that can be used by enterprises to allow data agents to take actions such as making modifications to the data, Gultekin said.

Inside Snowflake Intelligence

The Snowflake Intelligence platform is a combination of multiple capabilities that Snowflake released earlier, including Cortex AI, Cortex Search, Cortex Analyst, and the Horizon Catalog.

“Snowflake Intelligence uses Snowflake Cortex AI as the generative AI engine to access industry-leading large language models and retrieval services for responses grounded in enterprise data, which include Cortex Analyst for structured data and Cortex Search for unstructured data,” Gultekin said.

Cortex is a fully managed (serverless) service inside the Data Cloud that is designed to provide enterprises with the building blocks to use LLMs and AI without requiring any expertise in managing complex GPU-based infrastructure.

Separately, Cortex Search and Cortex Analyst, introduced earlier this year, was designed to help enterprises build chatbots that could answer questions about an enterprise’s data using natural language.

Snowpark inside Snowflake handles the custom code execution, such as Python, and the external API calling.

The agents created via the Snowflake Intelligence platform are natively integrated with the Horizon Catalog, which makes the agents compatible with open table formats such as Apache Iceberg and Polaris.

Harnessing the Cortex Chat API capabilities

Snowflake’s Intelligence platform will also harness Cortex Chat API’s capabilities, according to Gultekin.

Cortex Chat API, which is expected to enter public preview soon, is aimed at helping developers connect the chat application front-end with Snowflake and ensure that answers to questions or queries from users are grounded in enterprise data.

The API, according to Gultekin, combines structured and unstructured data into a single REST API call that helps developers make use of retrieval-augmented generation (RAG), which is useful for creating AI-based applications.

Other Cortex updates, such as Cortex Knowledge Extensions, can also be made use of by the platform, the company said.

Cortex Knowledge Extensions, which will be available inside the Snowflake Marketplace and are currently in preview, are designed to provide data teams a way to enrich enterprise AI chatbots with content from third-party providers, such as research or newspaper publications.

The ability of data agents to take actions on behalf of a user makes the Snowflake Intelligence platform similar to several agentic AI offerings introduced by vendors such as Salesforce, Microsoft, Anthropic, IBM, and ServiceNow.

The platform also seems very similar to other offerings, especially in terms of how a low-code or a no-code platform is used to create the agent and later used to manage it.

Snowflake Connector for SharePoint, currently in public preview, can also be used via the Intelligence platform. The connector allows data teams to access data without the need to manually set up any pipelines, Gultekin explained.

A natural evolution

Bradley Shimmin, Omdia’s chief analyst for AI & data analytics, sees the combination of Snowlake Cortex AI and Snowflake ML as “the natural evolution” of the company’s objectives, enabling developers to deploy new agentic processes alongside more mature AI technologies to build more mature and complex applications.

“I think what we’re seeing here is Snowflake attempting to match pace with Salesforce, which rolled out a pretty mature and comprehensive agent platform, Agentforce, a month or two ago,” he said.

Shimmin expects Snowflake to focus on automating functions such as writing back generated information to the datebase, a boon for data teams struggling to keep up with business demands.

And while he he sees Snowflake and its partners creating pre-built agentic workflows for enterprises to adopt at some point in the future, “Early adopters of Snowflake Intelligence will be building out their agentic processes using Cortex AI to set these up on a case-by-case basis,” he said.

Snowflake is yet to announce the general availability of the Intelligence platform.

]]>
https://www.infoworld.com/article/3603375/snowflake-bares-its-agentic-ai-plans-by-showcasing-its-intelligence-platform.html 3603375Artificial Intelligence, No Code and Low Code
Why your AI models stumble before the finish line Tue, 12 Nov 2024 09:00:00 +0000

In 2023, enterprises across industries invested heavily in generative AI proof of concepts (POCs), eager to explore the technology’s potential. Fast-forward to 2024, companies face a new challenge: moving AI initiatives from prototype to production.

According to Gartner, by 2025, at least 30% of generative AI projects will be abandoned after the POC stage. The reasons? Poor data quality, governance gaps, and the absence of clear business value. Companies are now realizing that the primary challenge isn’t simply building models — it’s ensuring the quality of the data feeding those models. As companies aim to move from prototype to production of models, they’re realizing that the biggest roadblock is curating the right data.

More data isn’t always better

In the early days of AI development, the prevailing belief was that more data leads to better results. However, as AI systems have become more sophisticated, the importance of data quality has surpassed that of quantity. There are several reasons for this shift. Firstly, large data sets are often riddled with errors, inconsistencies, and biases that can unknowingly skew model outcomes. With an excess of data, it becomes difficult to control what the model learns, potentially leading it to fixate on the training set and reducing its effectiveness with new data. Secondly, the “majority concept” within the data set tends to dominate the training process, diluting insights from minority concepts and reducing model generalization. Thirdly, processing massive data sets can slow down iteration cycles, meaning that critical decisions take longer as data quantity increases. Finally, processing large data sets can be costly, especially for smaller organizations or startups.

Organizations must strike a delicate balance between having enough data to train robust models and ensuring that it’s the right data. This means moving beyond data accumulation and focusing on data quality. By investing in practices like cleaning, validation, and enrichment, companies can ensure that their AI models are not only built on a solid foundation of high-quality data but are also well-prepared to scale and perform effectively in real-world production environments.

The price of poor data quality

A study by IBM found that poor data quality costs the United States economy around $3.1 trillion annually. Across industries, this issue is the root cause of AI initiatives stalling after proof of concept, draining resources and blocking companies from achieving full production-scale AI.

Beyond direct financial losses, failed AI projects incur significant indirect costs, including wasted time and computational resources. Most critically, these failures represent missed opportunities for a competitive advantage and can damage both internal and external reputations. Repeated failures can create a culture of risk aversion, stifling the very innovation that AI promises to deliver.

Research indicates that data scientists spend approximately 80% of their time preparing and organizing data before they can conduct any meaningful analysis.

The key characteristics of high-quality data

To overcome the root challenge of poor data quality, high-performance AI data sets must exhibit five key characteristics:

  1. Accuracy in reflecting real-world scenarios,
  2. Consistency in format and structure,
  3. Diversity to enhance adaptability,
  4. Relevance to specific objectives, and
  5. Ethical considerations in data collection and labeling.

To illustrate the importance of these characteristics, consider an example from Automotus, a company that automates payments for vehicle unloading and parking. The company faced challenges with poor data quality, including duplicate and corrupt images, which hindered their ability to convert vast amounts of image data into labeled training data sets for their AI models. To address these issues, the company used data quality tools to efficiently curate and reduce their data set by removing the bad examples—achieving a 20% improvement in mean average precision (mAP) for their object detection models. While the data reduction enhanced model accuracy, it further led to a 33% reduction in labeling costs, demonstrating that investing in data quality can yield both performance improvements and economic benefits.

How to achieve high-quality data

To navigate the challenges of AI development, organizations should take the following concrete steps to enhance their data practices:

  1. Establish clear data governance policies: Organizations should create comprehensive data governance policies that outline roles, responsibilities, and standards for data management. These guidelines ensure uniform data quality throughout the organization, reducing the risk of poor data impacting decision-making.
  2. Implement rigorous data cleaning techniques: Employ techniques such as outlier detection, imputation for missing values, and normalization to maintain the integrity of data sets. These practices help ensure that the data used for AI models is accurate and reliable.
  3. Invest in accurate labeling processes: High-quality labels are essential for model precision. Automated data labeling can offer significant advantages over manual labeling by reducing costs and streamlining the process. However, a hybrid approach that combines automated tools with human oversight can enhance accuracy by leveraging the strengths of both methods.
  4. Source data from diverse and reliable sources: Companies should seek diverse data sources to reduce bias and improve model performance. Examples include public data sets, industry-specific databases, and third-party data providers. Ensuring these sources are credible is crucial for maintaining data quality.
  5. Leverage advanced data management tools: To ensure ongoing AI performance, leverage advanced data management tools to continuously curate and update training data sets. Data distributions can change over time in production environments, and these tools can help companies adapt data sets accordingly.

Elevate data quality to scale AI

The demand for high-quality data will only grow as AI adoption increases. Gartner predicts that by 2025, enterprises will process 75% of their data outside traditional data centers or the cloud, highlighting the need for new strategies to maintain data quality in distributed environments. To confront these obstacles, key innovations are emerging in the field of data quality, including automated data checks, machine learning for data cleaning, privacy-preserving methods for training models on distributed data, and the generation of synthetic data to enhance real data sets.

These advancements are making it possible — and easy — for every company to create a data-centric culture. By prioritizing data quality, companies aren’t merely avoiding pitfalls, but unlocking AI’s full potential and setting new industry standards. It’s time to rally around the power of quality data — not just for competitive advantage, but to elevate the entire AI ecosystem. As AI continues to mature, the question isn’t “Do we have enough data?” Instead, it’s time to ask, “Do we have the right data to power the AI solutions of tomorrow?”

 Ulrik Stig Hansen is co-founder and president of Encord, an AI data development platform built to help companies manage and prepare their data for AI.

Generative AI Insights provides a venue for technology leaders—including vendors and other outside contributors—to explore and discuss the challenges and opportunities of generative artificial intelligence. The selection is wide-ranging, from technology deep dives to case studies to expert opinion, but also subjective, based on our judgment of which topics and treatments will best serve InfoWorld’s technically sophisticated audience. InfoWorld does not accept marketing collateral for publication and reserves the right to edit all contributed content. Contact doug_dineley@foundryco.com.

]]>
https://www.infoworld.com/article/3596776/why-your-ai-models-stumble-before-the-finish-line.html 3596776Artificial Intelligence, Data Quality, Generative AI, Software Development
Is your software architecture as clean as your code? Mon, 11 Nov 2024 09:00:00 +0000

Modern software must function smoothly within a diverse ecosystem, from on-premises monoliths to ever-evolving cloud-based microservices. Architectural choices made during software development, be they explicit or implicit, add complexity and create interdependencies, often leading to an increased risk of outages, incidents, and security issues as well as the accumulation of technical debt that impact the overall performance of the application.

How can you assess whether your software architecture holds up to scrutiny? Modern tools and practices allow organizations to go beyond code quality checks and implement principles that promote the health, stability, and scalability of their software architecture. This article explores why clean architecture is essential for supporting the growth, flexibility, and reliability of your software and provides practical steps for maintaining a healthy system architecture.

The principles of a clean software architecture

All systems are divided into independent modules, each responsible for specific tasks. The way in which these components are defined and how they interact with each other is the key factor in deciding the interdependencies of the system and therefore its complexity. The following principles of clean software architecture serve as the backbone of a well-structured system and promote flexibility while minimizing complexity:

Vertical separation

  • Separate business use cases into modules.
  • Ensure each module has its own persistence layer to save and retrieve data.
  • Minimize cross-module communication.

Vertical separation makes it easier to maintain and update individual modules based on a business case without affecting the whole system.

Horizontal separation

  • Communication should travel downwards (i.e., outbound → business logic layer → infrastructure), not upwards or sideways.
  • Separate infrastructure from the business logic layer, the brain of the application that contains a complex set of rules, computations, and decision-making processes that define the software’s core functionality.
  • Separate core business logic layer modules from outbound modules, interfacing with external users or systems.

Horizontal separation allows the creation of core modules that handle the most critical business logic while keeping them stable, reusable, and independent of external systems. In contrast to core modules, outward-facing modules handle interactions with external users or systems and rely on core services for their functionality but are less stable and more flexible by design.

Qualification

A module should be dedicated to a single purpose but not every purpose warrants a separate module. A well-defined task could potentially require a separate module but it must be qualified as such. Key qualifiers are business role, reuse, and scale.

  • Business: The task comprises a clear and distinct business scenario.
  • Reuse: The task is used in multiple different scenarios.
  • Scale. The task comprises its own unit of scale.

Note that dedication can go too far. Over-dedication leads to an excessive number of modules, increasing complexity on multiple levels (management, development, network, maintenance, etc.).

The principles of vertical separation, horizontal separation, and qualification enable developers to meet current requirements, adapt to future needs, and minimize complexity and technical debt. By ensuring modularity and minimizing dependencies, you ensure that modules can be developed, maintained, and scaled independently, improving system reliability without adding complexity.

The benefits of a clean software architecture

Clean architecture practices ensure that your software remains efficient, resilient, and scalable. Neglecting these principles can lead to mounting architectural technical debt, potentially costing organizations a significant loss in revenue. This financial impact stems from several factors including decreased system resiliency causing more frequent outages, missed market opportunities due to delayed launches and performance issues, customer churn as competitors offer more reliable solutions, and increased infrastructure costs to manage scalability problems.

Clean architecture offers several key benefits that significantly enhance software development and maintenance.

  • Improved system quality: Clean architecture results in a more maintainable and scalable system that adapts to changing requirements with minimal disruption.
  • Reduced technical debt: Thoughtful architectural decisions minimize debt, making future changes easier and less costly.
  • Enhanced developer productivity: A well-structured architecture makes it easier for developers to understand, modify, and extend the system, increasing productivity and reducing onboarding time for new team members.

How organizations can promote clean architecture

While having comprehensive guidelines to define the essential attributes of your architecture is important, relying on architecture quality gates often proves ineffective. Without robust tools and a deep understanding of architectural nuances, gaps in enforcement will leave your system vulnerable to design flaws. Instead of relying on these traditional checkpoints, organizations should adopt proactive strategies that address architectural challenges throughout the development process, ensuring a more resilient and maintainable architecture.

To promote a well-understood architecture, consider the following practices.

Establish processes to measure, prioritize, and remediate technical debt.

  • Measure: Leadership should regularly assess technical debt to understand its impact before it becomes critical.
  • Prioritize: Application owners should allocate resources to address the most pressing issues, aligning remediation with business needs.
  • Remediate: The development team should continuously address technical debt as part of the software development life cycle to ensure long-term architectural health.

Use AI-driven architectural observability and governance tools.

Architectural observability provides real-time insights into whether your architecture supports or obstructs your product strategy. These tools allow organizations to enforce good design principles by detecting issues in the architecture, suggesting improvements, and tracking the impact of changes over time. By detecting issues early, organizations can make data-driven decisions to mitigate risks and improve system resilience.

Provide training and resources for engineering teams.

Offer ongoing education to ensure teams understand and apply architectural principles in their daily work. This empowers them to make informed decisions, promoting continuous improvement.

A clean software architecture is essential for building robust systems that ensure application scalability, resiliency, and engineering velocity. Taking a top-down approach to technical debt remediation and performing regular evaluations in the development process allows organizations to find and fix the root causes of architectural issues, cut down technical debt, and nurture a culture of excellence in architecture. By focusing on proactive measures and continuous improvement, organizations can keep their software architecture in optimal condition—prepared to tackle both current and future challenges.

Ori Saporta is vice president of engineering and co-founder at vFunction.

New Tech Forum provides a venue for technology leaders—including vendors and other outside contributors—to explore and discuss emerging enterprise technology in unprecedented depth and breadth. The selection is subjective, based on our pick of the technologies we believe to be important and of greatest interest to InfoWorld readers. InfoWorld does not accept marketing collateral for publication and reserves the right to edit all contributed content. Send all inquiries to doug_dineley@foundryco.com.

]]>
https://www.infoworld.com/article/3589545/is-your-software-architecture-as-clean-as-your-code.html 3589545Application Life Cycle Management, Software Development