You searched for tutorials - Stackify https://stackify.com/ Wed, 15 May 2024 12:11:06 +0000 en-US hourly 1 https://wordpress.org/?v=6.4.4 https://stackify.com/wp-content/uploads/2023/02/favicon.png You searched for tutorials - Stackify https://stackify.com/ 32 32 How to Use Dependency Injection in Azure Functions https://stackify.com/how-to-use-dependency-injection-in-azure-functions/ Tue, 30 Jan 2024 18:52:01 +0000 https://stackify.com/?p=42680 Azure Functions is a powerful function as a service (FaaS) tool in the Microsoft Azure cloud computing service. Built to create event-driven, scalable, serverless computing services and applications, Azure Functions enable developers to focus on code logic without worrying about application infrastructure. The service also simplifies scaling apps and reduces costs, users only pay for resources consumed.

However, how developers manage dependencies is a growing concern, as time goes on and applications grow more and more complex. Dependency injection in Azure Functions is a great way to optimize applications and improve the developer experience when using Azure Functions. 

In this guide, we’ll cover:

  • What dependency injection in Azure Functions is
  • Advantages of using dependency injection with Azure Functions
  • How to use dependency injection in Azure Functions

Let’s get started.

What Is Dependency Injection in Azure Function?

Dependency injection is a software design methodology where an object supplies the dependencies of another object to help enhance the modularity, robustness, testability and maintainability of your code. This concept isn’t just specific to Azure Functions; it’s pretty popular in other languages and technologies like .Net Core.

The main idea behind dependency injection is to achieve the inversion of control (IOC) and loose coupling between classes and their dependencies.

Inverting the control means that a particular portion of an application receives its benefits or control from a flow handled by another portion of the application.

Now, taking this concept to Azure Functions, dependency injection enables you to inject dependencies into your Azure Functions, thus ensuring you can write more modular code and manage dependencies much better.

Dependency injection is done by an assembler rather than by the objects themselves, so understanding dependency injection technique is critical.

Also Read-https://stackify.com/how-to-catch-all-exceptions-in-python/

Why Is Dependency Injection Important?

For starters, dependency injection permits you to make your systems loosely coupled. Dependency injection decouples the implementations of classes from the implementations of other classes’ dependencies.

This process becomes possible by separating the usage of your class from the creation of one. This separation further improves reusability and limits how your lower-level classes are impacted. 

Other advantages of dependency injection are:

  • Aids in following the SOLID object-oriented design principles, as interfaces are used more and help reduce coupling between components
  • Ensures applications are more testable, maintainable and reusable. By externalizing configuration details into configuration files, the client’s knowledge of how dependencies are implemented is taken out
  • Makes the reuse of business logic implementations easier within different parts of your codebase and gives you more modularized and reusable code
  • Simplifies code maintenance, as reusable code is easier to maintain
  • Reduces the cost of ownership with more straightforward debugging and feature implementations

Implementing this principle in Azure Functions ensures a structured approach to managing dependencies and a robust application. You can learn more about dependency injection with code examples and how it relates to SOLID principles in Stackify’s recent tutorial.

How to Implement Dependency Injection in Azure Functions

To maximize the benefits of the tutorials in this guide, you’ll need the following: 

Creating Azure Functions Using Visual Studio

Let’s start by creating an Azure Functions app in Visual Studio. Azure Functions applications are event-driven, serverless computing platforms.

To do this:

  1. Open Visual Studio code or Visual Studio. I will be using Visual Studio
  2. Go to File and select New
  3. Search for Azure Functions in the search box. Click it
  4. Give the project a name and click Create. This name should not have underscores, hyphens or other non-alphanumeric characters. I will name my project “SampleStackify

5. Select Http trigger. Azure Functions supports many trigger points, such as HTTP and queue triggers

6. Then, click Create to create the Function

These steps will automatically create our first Azure Function. You can open the “Function1.cs” file to see the generated function.

Next, we must add interfaces and classes for the dependency injection.

Creating Interfaces & Classes for Dependency Injection

We must create the service or some classes we want to inject into our Azure Function.

However, before creating the class, we need to create an interface and the class that implements this interface.

To achieve this:

  1. Right-click on Function
  2. Then, select Add followed by New Folder. You can name this folder “Services
  3. Inside this folder, right-click again and select Add
  4. Under Add, select New File to create the interface
  5. Select Interface from the list of templates available
  6. You can name this interface “IGreeterService

Next, edit the definition of IGreeterService using the syntax below.

public interface IGreeterService

{
    string GetGreeting(string name);
}
The file should look like this:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleStackify.Services
{

    public interface IGreeterService

    {
        string GetGreeting(string name);
    }
}

Then, we must create a new class, “GreeterService,” to heredit our “iGreeterService” interface.

To create this class:

  1. Right-click on the “Services” folder
  2. Select Class and name it “GreeterService”

Then, edit the template generated using the syntax below:

public class GreeterService : IGreeterService
{
    public string GetGreeting(string name)
    {
        return $"Hello, {name}. This function executed successfully.";
    }
}

This GreeterService.cs file will look like this:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleStackify.Services
{
    public class GreeterService : IGreeterService
    {
        public string GetGreeting(string name)

        {
            return $"Hello, {name}. This function executed successfully.";
        }

    }
}

Creating a Startup Class in Azure Functions to Inject Dependency

We’ll need to create another class named “Startup” to handle all the dependencies we want to achieve.

You should right-click on your app name, “SampleStackify,” and select Class. Next, name this class “Startup.”

Before creating our startup class, we must add the Microsoft.azure.functions.extension and Microsoft.extensions.http Nuget packages.

You can accomplish this by right-clicking and selecting Manage Nuget packages.

Then, navigate to the browse menu and search for Microsoft.azure.functions.extension.

Click on install.

Similarly, search for Microsoft.extensions.http and click on Install. You’ll need to accept the license agreement.

Once done, return to the “Startup” class and write the code below. Doing this will register the service we want to inject and provides the mapping of the interface to the class.

The syntax for our Startup.cs file will look like this:












using Microsoft.Azure.Functions.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;
using SampleStackify.Services;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace SampleStackify

{
    public class Startup : FunctionsStartup
    {
        public override void Configure(IFunctionsHostBuilder builder)
        {
            builder.Services.AddScoped<IGreeterService, GreeterService>();
        }
    }
}

We need to add the code below into Function1.cs to inject dependency. First, we need to declare the two variables to handle our client.

private readonly ILogger<Function1> _logger;
private readonly IGreeterService _greeterService;
The final Function1.cs will look like this:
using Microsoft.Azure.Functions.Worker;
using Microsoft.Azure.Functions.Worker.Http;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using SampleStackify.Services;
using System.Net;
using System.Net.Http;
using System.Threading.Tasks;

namespace SampleStackify
{
    public class Function1
    {
        private readonly ILogger<Function1> _logger;
        private readonly IGreeterService _greeterService;

        public Function1(ILogger<Function1> logger, IGreeterService greeterService)

        {
            _logger = logger;

            _greeterService = greeterService;
        }

        [Function("Function1")]

        public async Task<HttpResponseData> Run(

            [HttpTrigger(AuthorizationLevel.Function, "get", "post")] HttpRequestData req,

            FunctionContext context)

        {

            _logger.LogInformation("C# HTTP trigger function processed a request.");

            var response = req.CreateResponse(HttpStatusCode.OK);

            response.Headers.Add("Content-Type", "text/plain; charset=utf-8");

            var name = req.Query["name"];

            var requestBody = await req.ReadAsStringAsync();

            dynamic data = JsonConvert.DeserializeObject(requestBody);

            name = name ?? data?.name;


            string responseMessage = string.IsNullOrEmpty(name)

                ? "Welcome to Azure Functions!"

                : _greeterService.GetGreeting(name);

            response.WriteString(responseMessage);

            return response;
        }
    }
}

We can now run our app to start the Azure Function.

That’s it. We’ve now injected dependency into our Azure Function app.

Challenges & Troubleshooting Common Issues

One common challenge is the misconfiguration of service. This can be remediated by ensuring the FunctionsStartup class is correctly and accurately configured with the necessary service registrations. You should also ensure that your dependencies have the appropriate constructors, as mismatches can lead to runtime errors.

Another challenge is the incorrect scoping of dependencies and resolving circular dependencies. These issues can also be avoided by making sure you use and verify the lifetime (transient, scoped or singleton) that aligns with Function requirements and analyzing the relationships between injected services. 

You can also troubleshoot these issues by checking the Azure Functions logs for diagnostic insights and any initialization errors or failures in service resolution.

Best Practices When Using Dependency Injection in Azure Functions

Let’s explore best practices to should follow when using dependency injection in Azure Functions.

1. Unit testing helps in the early detection of issues, especially when we make changes or design our Functions. By creating more unit-testable Functions, we can ensure that the individual aspect of our code works as expected without testing the entire script.

In Azure Functions, unit testing comes in handy because we often have small, independent units of code. 

var response1 = await function.Run(request1, context);

Assert.AreEqual(HttpStatusCode.OK, response1.StatusCode);

Assert.IsTrue(response1.Headers.TryGetValue("Content-Type", out var contentType1));

Assert.AreEqual("text/plain; charset=utf-8", contentType1);

var responseBody1 = await response1.ReadAsStringAsync();

Assert.AreEqual("Welcome to Azure Functions!", responseBody1);

The script above is an example of a unit test that verifies our Azure Function (Function1) is executed with a specific request (request1). The test also checks that our Function’s response has the expected HTTP status code, content type and response body content.

2. Log when possible! Logging can track the process right from the initialization of dependencies. These logs provide insights that can be used for troubleshooting and monitoring. For example, if a service injected fails to initialize or execute, logs can reveal the specific point of failure, identify bottlenecks and make diagnosing and fixing problems easier.

3. Leveraging the FunctionsStartup class in Azure Functions helps organize our service configuration for dependency injection. One of the best ways to do this is by registering your services using the IFunctionsHostBuilder provided by the Azure Functions runtime inside the Configure method of the FunctionsStartup class. Here, you can define the dependencies to avoid scattering them throughout different parts of your application.

To establish more readability, you should also apply the assembly.

4. FunctionsStartup(typeof(MyNamespace.Startup)) attribute at the assembly level to specify the type of your FunctionsStartup class. This attribute will inform your Azure Functions runtime about the custom startup class to use when configuring the function app, thus acting as a line between your startup logic and the Azure Functions runtime.

Wrapping Up

Azure Functions lets you build serverless, compute-on-demand, lightweight applications. By weaving together the functionalities of Azure Functions and your technical understanding of dependency injections, developers can create more efficient and robust applications.

Of course, we’ve just scratched the surface of what can be done with dependency injection in Azure Functions. As you build, you should monitor your applications and Azure Functions with solutions like Retrace. A comprehensive, developer-friendly APM solution, Retrace monitors the performance of your virtual machines, Azure Stack and deployments.

You can give Retrace a go by starting with a free trial today!

Also Read-https://stackify.com/rack-mini-profiler-a-complete-guide-on-rails-performance/

This post was written by Ifeanyi Benedict Iheagwara. Ifeanyi is a data analyst and Power Platform developer who is passionate about technical writing, contributing to open source organizations, and building communities. Ifeanyi writes about machine learning, data science, and DevOps, and enjoys contributing to open-source projects and the global ecosystem in any capacity.

]]>
A Basic Introduction to OpenTelemetry Python https://stackify.com/a-basic-introduction-to-opentelemetry-python/ Tue, 16 Jan 2024 15:55:40 +0000 https://stackify.com/?p=42629 Think of a tool that simplifies application monitoring and helps developers and staff trace, collect logs and measure performance metrics. That is what OpenTelemetry Python provides. OpenTelemetry (OTel) Python acts as a guiding light, offering insights into the behaviors and interactions of complex, distributed systems and enabling a deeper understanding of performance bottlenecks and system dependencies. The significance of OTel lies in its pivotal role in modern software development. OTel is crafted to address the challenges microservices architectures and cloud-native environments pose. Providing a standardized approach to observability facilitates the collection and analysis of crucial data points, which paves a way for continuous performance enhancement.

Understanding how software works behind the scenes is key in today’s tech world. OpenTelemetry helps you see into this complex world, showing how your apps perform and behave. By using OTel, developers can quickly find and fix issues, making their software stronger and better.

This post will guide you through the fundamentals of OpenTelemetry Python. You will gain a comprehensive understanding of key concepts, practical applications and real use cases, enabling you to harness the power of OTel to simplify monitoring of cloud-native software applications.

Key Concepts of OpenTelemetry Python

OpenTelemetry helps analyze any software application data in the form of traces, logs and metrics. Providing a unified approach to instrumenting applications and collecting telemetry data across diverse environments, OTel is an invaluable tool for understanding and optimizing distributed systems. Now, let’s unravel some of its pivotal concepts.

Distributed Tracing

Distributed tracing tracks the flow of requests and operations across multiple services or components in a distributed system. By creating traces, which are essentially timelines of events, developers can identify performance bottlenecks, pinpoint errors and gain insights into the overall behavior of their system.

OpenTelemetry Python provides a powerful distributed tracing API that allows developers to instrument their code and generate traces easily. Traces are exportable to various back ends for analysis and visualization, providing a comprehensive view of the system’s performance and health.

Logs

Logs are a fundamental part of monitoring and debugging applications. Providing a stream of events and messages that record the behavior of the system, logs make it easier to identify errors, track user activity and understand system behavior.

OpenTelemetry Python integrates seamlessly with logging frameworks, enabling developers to collect and export logs in a standardized format. This integration allows for centralized logging and analysis, providing a holistic view of the system’s activity and ensuring that crucial data about an application’s behavior is readily available for analysis, troubleshooting, and debugging.

Metrics

Metrics are numerical values representing the state or behavior of a system over time. They provide a quantitative measure of system performance, resource utilization, and other key indicators like response times, error rates or resource usage.

OpenTelemetry Python supports the collection and export of metrics, enabling developers to monitor key performance indicators (KPIs) and identify trends or anomalies in system behavior. This information is crucial for optimizing resource allocation, identifying performance bottlenecks and ensuring overall system health.

Getting Started With OpenTelemetry Python

OpenTelemetry Python serves as a potent tool for collecting essential data to monitor and observe applications in action. Here, we’ll walk through the initial setup and demonstrate how to harness OTel capabilities for effective instrumentation within a basic Python application.

Installation & Setup

Installing the OpenTelemetry Python Package

The first step involves installing the OpenTelemetry Python package. Utilize Python’s package manager, PIP, to install the necessary components. Execute the following command in your terminal or command prompt:

$ pip install opentelemetry-api
$ pip install opentelemetry-sdk

Configuration Setup for Basic Instrumentation

After installing the OpenTelemetry Python package, the next crucial step involves setting up the basic configuration for instrumentation within your Python application. This configuration defines how OpenTelemetry collects and exports data.

from opentelemetry import trace
from opentelemetry.sdk.trace import TracerProvider
from opentelemetry.sdk.resources import Resource
from opentelemetry.sdk.trace.export import ConsoleSpanExporter
from opentelemetry.sdk.trace.export import BatchSpanProcessor

We have imported the necessary modules from OTel. These imports serve the following purpose:

  • TracerProvider: Represents the core component responsible for managing tracing resources and providing tracers to the application.
  • Resource: Defines attributes (like service name) describing the application, aiding in the identification and categorization of traces.
  • ConsoleSpanExporter: An exporter directing trace spans to the console, facilitating visibility and demonstration of traced data for testing or learning purposes.
  • BatchSpanExporter(ConsoleSpanExporter): Sets up a span processor that processes spans before exporting, linking to the console exporter for handling trace spans.
  • trace.get_tracer(name): Retrieves a tracer for use within the application, allowing the creation of spans to encapsulate specific operations or blocks of code for tracing purposes.

Basic Instrumentation

Adding Instrument to a Sample Python Application

In this section, you’ll learn how you can export the trace spans to the console for a sample Python application. Below is a simple Python application of a loop printing the numbers from 0 to 5. Now you have to trace the working of each iteration and get the metrics. Below demonstrates how OpenTelemetry helps you.

# simple application
def main():
    print("Starting the application...")
    for i in range(5):
        process_data(i)
    print("Application finished.")

def process_data(num):
    print(f"Processing data: {num}")

if __name__ == "__main__":

Integrating Tracing

Now let’s instrument the basic application with OTel to trace the process_data() function.

# let's apply tracing
def main():
    # setup OpenTelemetry tracing
    resource = Resource.create({"service.name": "my-service"})
    trace.set_tracer_provider(TracerProvider(resource=resource))
    span_processor = BatchSpanProcessor(ConsoleSpanExporter())
    trace.get_tracer_provider().add_span_processor(span_processor)
    tracer = trace.get_tracer(__name__)

    print("Starting the application...")
    with tracer.start_as_current_span("Main-Span"):
        for i in range(5):
            process_data(tracer, i)
    print("Application finished.")

def process_data(tracer, num):
    with tracer.start_as_current_span(f"processing-Span-{num}"):
        print(f"Processing data: {num}")

if __name__ == "__main__":
    main()

The process_data() function is now wrapped in a span created by the tracer, which represents each iteration of the data processing. This simple instrumentation showcases how OTel can be applied to monitor and trace specific operations within a Python application. Adjust and expand this instrumentation as needed to capture additional details or specific segments of interest within your application’s codebase.

  • tracer.start_as_current_span(…): Context manager that creates a new span for a block of code. Spans represent individual operations or sections of code being traced.
  • process_data(tracer, i): Calls the process_data() function, which starts a new span for each iteration to trace the processing of data.

Integrating Logging

Begin by integrating logging into the application alongside tracing. Modify the existing code to include logging statements using Python’s logging module or any preferred logging framework.

import logging
# configure logging
logging.basicConfig(level=logging.INFO)

def main():
    # ... (existing code remains the same)
    logging.info("Starting the application...")
    with tracer.start_as_current_span("main"):
        for i in range(5):
            process_data(tracer, i)
    logging.info("Application finished.")

Here, logging.info() statements are added at the start and end of the application and can be inserted at relevant points within the code to capture information during execution.

Integrating Metrics

Next, integrate metrics to capture relevant data points about the application’s performance. Use OTel metrics functionalities or other metric collection libraries to define and record metrics.

from opentelemetry import metrics

# create a meter to register and manage metrics
meter = metrics.get_meter(__name__)

# define a counter metric
requests_count = meter.create_counter(name="requests_count", description="Number of requests processed")

def main():
    # ... (existing code remains the same)
    with tracer.start_as_current_span("main"):
        for i in range(5):
            process_data(tracer, i)
            requests_count.add(1)  # Increment the counter on each iteration

In this example, a metric named requests_count is defined, and within the application’s main loop, the metric is incremented for each iteration of the loop.

By incrementally integrating logging and metrics alongside tracing in the same application, developers can enhance observability by capturing logs, tracing spans, and monitoring important metrics related to the application’s behavior and performance.

Common Challenges & Solutions

Addressing common issues during setup and offering troubleshooting tips for smooth integration is crucial for ensuring a successful implementation of instrumentation within a Python application.

Addressing Common Issues During Setup

  1. Dependency version conflicts: Check for any conflicting versions or dependencies between OpenTelemetry and other libraries or frameworks used within the application. Resolve version conflicts to ensure compatibility and smooth operation.
  2. Misconfigured exporters: Incorrect configuration of exporters or span processors might lead to spans not being exported or displayed correctly. Verify the exporter setup and ensure it’s the correct configuration to handle and export spans.
  3. Missing instrumentation libraries: Ensure all necessary instrumentation libraries or modules for tracing, logging, or metrics are installed and correctly configured within the application. Missing or improperly configured instrumentation might lead to incomplete or inaccurate data collection.

Troubleshooting Tips for a Smooth Integration

  1. Logging and debugging setup: Configure robust logging and debugging mechanisms alongside tracing to effectively capture and analyze issues or errors encountered during the integration process.
  2. Incremental integration approach: Implement instrumentation incrementally, focusing on one aspect at a time (e.g., tracing first, then logging, followed by metrics). This step-by-step approach allows for better isolation and debugging of issues that might arise during integration.
  3. Testing and validation: Perform thorough testing of the instrumentation setup by generating test scenarios and verifying if the expected traces, logs, or metrics are being captured accurately. Use test cases to validate the functionality and correctness of the integrated instrumentation.
  4. Community support and resources: Leverage community forums, documentation, and resources provided by the instrumentation libraries or tools (e.g., OpenTelemetry documentation, forums, GitHub repositories). Seek assistance and advice from the community to troubleshoot any integration challenges encountered.

Practical Use Cases of OpenTelemetry Python

OpenTelemetry is a very useful tool that helps monitor the performance of various applications and application development workflows. In this section, you’ll learn about some real use cases of OpenTelemetry Python in performance monitoring.

Microservice Architecture

In a microservices-based application, numerous services interact to handle various functionalities. OpenTelemetry Python can effectively trace and monitor requests as they traverse through these distributed services. It helps in understanding the entire flow of a request, identifying performance bottlenecks, and diagnosing issues within and across services. Tracing capabilities makes it easier to pinpoint which microservice might be causing delays or errors, allowing for quick resolution and optimization.

Cloud-Native Deployments

When you’re deploying applications in cloud-native environments, understanding performance across diverse cloud services, platforms, or containers becomes vital. OpenTelemetry Python provides insights into how an application utilizes these cloud resources. It enables monitoring and observing the application’s behavior within cloud environments, allowing for better resource management, cost optimization, and performance enhancement.

Benefits of Using OpenTelemetry Python

  1. Unified observability: Standardized framework for collecting traces, logs, and metrics.
  2. Distributed tracing: Visibility into complex, distributed architectures for issue identification.
  3. Performance optimization: Proactive identification and resolution of performance issues.
  4. Troubleshooting & debugging: Contextual insights for faster issue resolution.
  5. Cost optimization: Resource consumption insights for better cost management.
  6. Compatibility & flexibility: Integration across diverse tech stacks and platforms.
  7. Community support & growth: Continual evolution and support through a thriving community.

Impacts of OpenTelemetry on Observability & Troubleshooting Capabilities

  1. Enhanced observability: Provides comprehensive insights into application behavior, interactions, and performance across distributed systems.
  2. Real-time monitoring: Facilitates real-time monitoring of system health, enabling proactive identification and resolution of issues.
  3. Efficient issue resolution: Accelerates issue resolution by providing detailed, contextual information for root cause analysis.
  4. Improved resource utilization: Assists in optimizing resource allocation and usage, leading to better cost management in cloud-native environments.
  5. Streamlined debugging: Simplifies debugging processes by providing visibility into code execution and service interactions.

Conclusion

After reading this article, you’ve gained a solid understanding of OpenTelemetry Python. You have explored its pivotal role in modern software observability. You’ve learned about fundamental concepts like tracing, logging, and metrics. You understand how OTel offers a unified framework to capture and analyze these crucial aspects of application behavior. 

From the setup to practical integration, you’ve seen how OTel empowers developers with unparalleled insights into distributed systems, which enables efficient troubleshooting and performance optimization.

This post was written by Gourav Bais. Gourav is an applied machine learning engineer skilled in computer vision/deep learning pipeline development, creating machine learning models, retraining systems, and transforming data science prototypes into production-grade solutions.

]]>
Top Java Software Errors: 50 Common Java Errors and How to Avoid Them https://stackify.com/refresh-top-java-software-errors-50-common-java-errors-and-how-to-avoid-them/ Thu, 12 Oct 2023 18:29:59 +0000 https://stackify.com/?p=42329 Imagine, you are developing Java software and suddenly you encounter errors. Where could have possibly gone wrong?

There are many types of errors that you will encounter while developing Java software, but most are avoidable. If you have an error monitoring tool such as Stackify Retrace, you can write code with ease.

In this article you will find:

  • 50 of the most common Java software errors
  • Code examples and tutorials to help you work around common coding problems

Read on to learn about the most common issues and their workarounds.

Compiler Errors

Compiler error messages are created when the Java software code is run through the compiler. It is important to remember that a compiler may throw many error messages for one error. So, fix the first error and recompile.

 1. “… expected”

This error occurs when something is missing from the code. Often this happens as result of a missing semicolon or closing parenthesis.

private static double volume(String solidom, double alturam, double areaBasem, double raiom) {
double vol;

    if (solidom.equalsIgnoreCase("esfera"){
        vol=(4.0/3)*Math.pi*Math.pow(raiom,3);
    }
    else {
        if (solidom.equalsIgnoreCase("cilindro") {
            vol=Math.pi*Math.pow(raiom,2)*alturam;
        }
        else {
            vol=(1.0/3)*Math.pi*Math.pow(raiom,2)*alturam;
        }
    }
    return vol;
}

Often this error message does not pinpoint the exact location of the issue. To find it:

  • Make sure all opening parenthesis have a corresponding closing parenthesis.
  • Look in the line previous to the Java code line indicated. This Java software error doesn’t get noticed by the compiler until further in the code.
  • Sometimes a character such as an opening parenthesis shouldn’t be in the Java code in the first place. So the developer didn’t place a closing parenthesis to balance the parentheses.

Check out an example of how a missed parenthesis can create an error (@StackOverflow).

2. “unclosed string literal”

The “unclosed string literal” error message is created when the string literal ends without quotation marks and the message will appear on the same line as the error.

 public abstract class NFLPlayersReference {

    private static Runningback[] nflplayersreference;

    private static Quarterback[] players;

    private static WideReceiver[] nflplayers;

    public static void main(String args[]){

    Runningback r = new Runningback("Thomlinsion");

    Quarterback q = new Quarterback("Tom Brady");

    WideReceiver w = new WideReceiver("Steve Smith");

    NFLPlayersReference[] NFLPlayersReference;


        Run();// {

        NFLPlayersReference = new NFLPlayersReference [3];

        nflplayersreference[0] = r;

        players[1] = q;

        nflplayers[2] = w;
 

            for ( int i = 0; i < nflplayersreference.length; i++ ) {

            System.out.println("My name is " + " nflplayersreference[i].getName());

            nflplayersreference[i].run();

            nflplayersreference[i].run();

            nflplayersreference[i].run();

            System.out.println("NFL offensive threats have great running abilities!");

        }

    }

    private static void Run() {

        System.out.println("Not yet implemented");

    }     
 
}

Commonly, this happens when:

  •         The string literal does not end with quote marks. This is easy to correct by closing the string literal with the needed quotation mark.
  •         The string literal extends beyond a line. Long string literals can be broken into multiple literals and concatenated with a plus sign (“+”).
  •         Quote marks that are part of the string literal are not escaped with a backslash (“\”).

Read a discussion of the unclosed string literal Java software error message. (@Quora)

3. “illegal start of an expression”

There are numerous reasons why an “illegal start of an expression” error occurs. It ends up being one of the less-helpful error messages. Some developers say it’s caused by bad code.

Usually, expressions are created to produce a new value or assign a value to a variable. The compiler expects to find an expression and cannot find it because the syntax does not match expectations. (@StackOverflow) It is in these statements that the error can be found.

} // ADD IT HERE

       public void newShape(String shape) {

        switch (shape) {
            case "Line":
                Shape line = new Line(startX, startY, endX, endY);
            shapes.add(line);
            break;
                case "Oval":
            Shape oval = new Oval(startX, startY, endX, endY);
            shapes.add(oval);
            break;
            case "Rectangle":
            Shape rectangle = new Rectangle(startX, startY, endX, endY);
            shapes.add(rectangle);
            break;
            default:
            System.out.println("ERROR. Check logic.");
        }
        }
    } // REMOVE IT FROM HERE
    }

Browse discussions of how to troubleshoot the “illegal start of an expression” error. (@StackOverflow)

4. “cannot find symbol”

This is a very common issue because all identifiers in Java need to be declared before they are used. When the code is being compiled, the compiler does not understand what the identifier means.

cannot findf symbol screenshot

There are many reasons you might receive the “cannot find symbol” message:

  • The spelling of the identifier when declared may not be the same as when it is used in the code.
  • The variable was never declared.
  • The variable is not being used in the same scope it was declared.
  • The class was not imported.

Read a thorough discussion of the “cannot find symbol” error and several code examples that create the same issue. (@StackOverflow)

5. “public class XXX should be in file”

The “public class XXX should be in file” message occurs when the class XXX and the Java program filename do not match. The code will only be compiled when the class and Java file are the same. (@coderanch)

package javaapplication3;  
   
 
  public class Robot {  
        int xlocation;  
        int ylocation;  
        String name;  
        static int ccount = 0;  
           
        public Robot(int xxlocation, int yylocation, String nname) {  
            xlocation = xxlocation;  
            ylocation = yylocation;  
            name = nname;  
            ccount++;         
        } 
  }
         
  public class JavaApplication1 { 
       
       
       
    public static void main(String[] args) {  
           
        robot firstRobot = new Robot(34,51,"yossi");  
        System.out.println("numebr of robots is now " + Robot.ccount);  
    }
  }

To fix this issue:

  • Name the class and file the same.
  • Make sure the case of both names is consistent.

See an example of the “Public class XXX should be in file” error. (@StackOverflow)

6. “incompatible types”

“Incompatible types” is an error in logic that occurs when an assignment statement tries to pair a variable with an incompatible type. It often comes when the code tries to place a text string into an integer — or vice versa. This is not a Java syntax error. (@StackOverflow)

test.java:78: error: incompatible types
return stringBuilder.toString();
                             ^
required: int
found:    String
1 error

There really isn’t an easy fix when the compiler gives an “incompatible types” message:

  • There are functions that can convert types.
  • Developer may need to change what the code is expected to do.

Check out an example of how trying to assign a string to an integer created the “incompatible types.”  (@StackOverflow)

7. “invalid method declaration; return type required”

This Java software errors message means the return type of a method was not explicitly stated in the method signature.

public class Circle
{
    private double radius;
    public CircleR(double r)
    {
        radius = r;
    }
    public diameter()
    {
       double d = radius * 2;
       return d;
    }
}

There are a few ways to trigger the “invalid method declaration; return type required” error:

  • Forgetting to state the type
  • If the method does not return a value then “void” needs to be stated as the type in the method signature.
  • Constructor names do not need to state type. But if there is an error in the constructor name, then the compiler will treat the constructor as a method without a stated type.

Follow an example of how constructor naming triggered the “invalid method declaration; return type required” issue. (@StackOverflow)

8. “method <X> in class <Y> cannot be applied to given types”

This Java software errors message is one of the more helpful error messages. It explains how the method signature is calling the wrong parameters.

RandomNumbers.java:9: error: method generateNumbers in class RandomNumbers cannot be applied to given types;
generateNumbers();

required: int[]

found:generateNumbers();

reason: actual and formal argument lists differ in length

The method called is expecting certain arguments defined in the method’s declaration. Check the method declaration and call carefully to make sure they are compatible.

This discussion illustrates how a Java software error message identifies the incompatibility created by arguments in the method declaration and method call. (@StackOverflow)

9. “missing return statement”

The “missing return statement” message occurs when a method does not have a return statement. Each method that returns a value (a non-void type) must have a statement that literally returns that value so it can be called outside the method.

public String[] OpenFile() throws IOException {

    Map<String, Double> map = new HashMap();

    FileReader fr = new FileReader("money.txt");
    BufferedReader br = new BufferedReader(fr);


    try{
        while (br.ready()){
            String str = br.readLine();
            String[] list = str.split(" ");
            System.out.println(list);               
        }
    }   catch (IOException e){
        System.err.println("Error - IOException!");
    }
}

There are a couple of reasons why a compiler throws the “missing return statement” message:

  • Omitted a return statement
  • The method did not return any value but type void was not declared in the method signature.

Check out an example of how to fix the “missing return statement” Java software error. (@StackOverflow)

10. “possible loss of precision”

“Possible loss of precision” occurs when more information is assigned to a variable than it can hold. If this happens, pieces will be thrown out. If this is fine, then the code needs to explicitly declare the variable as a new type.

A “possible loss of precision” error commonly occurs when:

  •         Trying to assign a real number to a variable with an integer data type.
  •         Trying to assign a double to a variable with an integer data type.

This explanation of Primitive Data Types in Java shows how the data is characterized. (@Oracle)

This error message usually occurs in Java when the program is missing the closing curly brace (“}”)

11. “reached end of file while parsing”

This error message usually occurs in Java when the program is missing the closing curly brace (“}”). Sometimes it can be quickly fixed by placing it at the end of the code.

public class mod_MyMod extends BaseMod

public String Version()

{

return "1.2_02";

}

public void AddRecipes(CraftingManager recipes)

{

   recipes.addRecipe(new ItemStack(Item.diamond), new Object[] {

  "#", Character.valueOf('#'), Block.dirt

   });

}

The above code results in the following error:

java:11: reached end of file while parsing }

Coding utilities and proper code indenting can make it easier to find these unbalanced braces.

This example shows how missing braces can create the “reached end of file while parsing” error message. (@StackOverflow)

12. “unreachable statement”

“Unreachable statement” occurs when a statement is written in a place that prevents it from being executed. Usually, this is after a break or return statement.

for(;;){

   break;

   ... // unreachable statement

}

int i=1;

if(i==1)

 ...

else

 ... // dead code

Often simply moving the return statement will fix the error. Read the discussion of how to fix unreachable statement Java software error. (@StackOverflow)

13. “variable <X> might not have been initialized”

This occurs when a local variable declared within a method has not been initialized. It can occur when a variable without an initial value is part of an if statement.

int x;

if (condition) {

x = 5;

}

System.out.println(x); // x may not have been initialized

Read this discussion of how to avoid triggering the “variable <X> might not have been initialized” error. (@reddit)

14. “Operator .. cannot be applied to <X>”

This issue occurs when operators are used for types, not in their definition.

operator < cannot be applied to java.lang.Object,java.lang.Object

This often happens when the Java code tries to use a type string in a calculation. To fix it, the string needs to be converted to an integer or float.

Read this example of how non-numeric types were causing a Java software error warning that an operator cannot be applied to a type. (@StackOverflow)

15. “inconvertible types”

The “inconvertible types” error occurs when the Java code tries to perform an illegal conversion.

TypeInvocationConversionTest.java:12: inconvertible types

found   : java.util.ArrayList<java.lang.Class<? extends TypeInvocationConversionTest.Interface1>>

required: java.util.ArrayList<java.lang.Class<?>>

lessRestrictiveClassList = (ArrayList<Class<?>>) classList;

                                                 ^

For example, booleans cannot be converted to an integer.

Read this discussion about finding ways to convert inconvertible types in Java software. (@StackOverflow)

16. “missing return value”

You’ll get the “missing return value” message when the return statement includes an incorrect type. For example, the following code:

public class SavingsAcc2

{

private double balance;

private double interest;

 

 public SavingsAcc2()

{

balance = 0.0;

interest = 6.17;

}

 public SavingsAcc2(double initBalance, double interested)

{

balance = initBalance;

interest = interested;

 }

 public SavingsAcc2 deposit(double amount)

{

balance = balance + amount;

return;

}

 public SavingsAcc2 withdraw(double amount)

{

balance = balance - amount;

return;

}

 public SavingsAcc2 addInterest(double interest)

{

balance = balance * (interest / 100) + balance;

return;

}

 public double getBalance()

{

return balance;

}

}

Returns the following error:

SavingsAcc2.java:29: missing return value

return;

^

SavingsAcc2.java:35: missing return value

return;

^

SavingsAcc2.java:41: missing return value

return;

^

3 errors

Usually, there is a return statement that doesn’t return anything.

Read this discussion about how to avoid the “missing return value” Java software error message. (@coderanch)

17. “cannot return a value from method whose result type is void”

This Java error occurs when a void method tries to return any value, such as in the following example:

public static void move()

{

    System.out.println("What do you want to do?");

    Scanner scan = new Scanner(System.in);

    int userMove = scan.nextInt();

    return userMove;

}

 

public static void usersMove(String playerName, int gesture)

{

    int userMove = move();

 

    if (userMove == -1)

    {

    break;

    }

Often this is fixed by changing to method signature to match the type in the return statement. In this case, instances of void can be changed to int:

public static int move()

{

    System.out.println("What do you want to do?");

    Scanner scan = new Scanner(System.in);

    int userMove = scan.nextInt();

    return userMove;

}

Read this discussion about how to fix the “cannot return a value from method whose result type is void” error. (@StackOverflow)

18. “non-static variable . . . cannot be referenced from a static context”

This error occurs when the compiler tries to access non-static variables from a static method (@javinpaul):

public class StaticTest {

   private int count=0;

   public static void main(String args[]) throws IOException {

       count++; //compiler error: non-static variable count cannot be referenced from a static context

   }

}

To fix the “non-static variable . . . cannot be referenced from a static context” error, try these two things:

  • Declare the variable as static in the signature.
  • Check on the code as it can create an instance of a non-static object in the static method.

Read this tutorial that explains what is the difference between static and non-static variables. (@sitesbay)

19. “non-static method . . . cannot be referenced from a static context”

This issue occurs when the Java code tries to call a non-static method in a non-static class. Here is an example:

class Sample

{

   private int age;

   public void setAge(int a)

   {

       age=a;

   }

   public int getAge()

   {

       return age;

   }

   public static void main(String args[])

   {

       System.out.println(“Age is:”+ getAge());

   }

}

Would return this error:

Exception in thread “main” java.lang.Error: Unresolved compilation problem:

       Cannot make a static reference to the non–static method getAge() from the type Sample

To call a non-static method from a static method is to declare an instance of the class calling the non-static method.

Read this explanation on what is the difference between non-static methods and static methods.

20. “(array) <X> not initialized”

You’ll get the “(array) <X> not initialized” message when an array has been declared but not initialized. Arrays are fixed in length so each array needs to be initialized with the desired length.

The following code is acceptable:

AClass[] array = {object1, object2}

       As is:

       AClass[] array = new AClass[2];

       …

       array[0] = object1;

       array[1] = object2;

       But not:

       AClass[] array;

       …

       array = {object1, object2};

Read this discussion of how to initialize arrays in Java software. (@StackOverflow)

Runtime Exceptions

Runtime exceptions are exception that can’t be caught during the compilation phase. They require running the actual application to encounter the error.

21. “ArrayIndexOutOfBoundsException”

This is a runtime error message that occurs when the code attempts to access an array index that is not within the values. The following code would trigger this exception:

String[] name = {“tom”, “dick”, “harry”};

       for(int i = 0; i<=name.length; i++) {
       System.out.print(name[i] +‘\n’);
       }

      Here’s another example (@DukeU):

      int[] list = new int[5];

      list[5] = 33;       // illegal index, maximum index is 4

Array indexes start at zero and end at one less than the length of the array. Often it is fixed by using “<” instead of “<=” when defining the limits of the array index.

Check out this example on how an index triggered the “ArrayIndexOutOfBoundsException” Java software error message. (@StackOverflow)

22.  “StringIndexOutOfBoundsException”

This is an issue that occurs when the code attempts to access a part of the string that is not within the bounds of the string. Usually, this happens when the code tries to create a substring of a string that is not of the same length as the parameter. Here’s an example (@javacodegeeks):

public class StringCharAtExample {

   public static void main(String[] args) {

       String str = “Java Code Geeks!”;

       System.out.println(“Length: “ + str.length());

       //The following statement throws an exception, because

       //the request index is invalid.

       char ch = str.charAt(50);

   }

}

Like array indexes, string indexes start at zero. When indexing a string, the last character is at one less than the length of the string. The “StringIndexOutOfBoundsException” Java software error message usually means the index is trying to access characters that aren’t there.

Here’s an example that illustrates how the “StringIndexOutOfBoundsException” can occur and how to fix it. (@StackOverflow)

23. “NullPointerException”

A “NullPointerException” will occur when the program tries to use an object reference that does not have a value assigned to it (@geeksforgeeks).

// A Java program to demonstrate that invoking a method

// on null causes NullPointerException

import java.io.*;

class GFG

{

   public static void main (String[] args)

   {

       // Initializing String variable with null value

       String ptr = null;

       // Checking if ptr.equals null or works fine.

       try

       {

           // This line of code throws NullPointerException

           // because ptr is null

           if (ptr.equals(“gfg”))

               System.out.print(“Same”);

           else

               System.out.print(“Not Same”);

       }

       catch(NullPointerException e)

       {

           System.out.print(“NullPointerException Caught”);

       }

   }

}

The Java program often raises an exception when:

  • A statement references an object with a null value.
  • Trying to access a class that is defined but isn’t assigned a reference.

Here’s a discussion of when developers encounter the “NullPointerException” error and how to handle it. (@StackOverflow)

24. “NoClassDefFoundError”

The “NoClassDefFoundError” will occur when the interpreter cannot find the file containing a class with the main method. Here’s an example from DZone (@DZone):

If you compile this program:

class A

{

   // some code

}

public class B

{

   public static void main(String[] args)

   {

       A a = new A();

   }

}

Two .class files are generated: A.class and B.class. Removing the A.class file and running the B.class file, will  get you the “NoClassDefFoundError”:

Exception in thread “main” java.lang.NoClassDefFoundError: A

       at MainClass.main(MainClass.java:10)

       Caused by: java.lang.ClassNotFoundException: A

       at java.net.URLClassLoader.findClass(URLClassLoader.java:381)

       at java.lang.ClassLoader.loadClass(ClassLoader.java:424)

       at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)

       at java.lang.ClassLoader.loadClass(ClassLoader.java:357)

This can happen if:

  • The file is not in the right directory.
  • The name of the class is not the same as the name of the file (without the file extension). Also, the names are case sensitive.

Read this discussion of why “NoClassDefFoundError” occurs when running Java software. (@StackOverflow)

25. “NoSuchMethodFoundError”

This error message will occur when the Java software tries to call a method of a class and the method no longer has a definition (@myUND):

Error: Could not find or load main class wiki.java

Often the “NoSuchMethodFoundError” Java software error occurs when there is a typo in the declaration.

Read this tutorial to learn how to avoid the error message “NoSuchMethodFoundError”. (@javacodegeeks)

26. “NoSuchProviderException”

“NoSuchProviderException” occurs when a security provider is requested that is not available (@alvinalexander):

javax.mail.NoSuchProviderException

When trying to find why “NoSuchProviderException” occurs, check:

  •         The JRE configuration.
  •         The Java_home is set in the configuration.
  •         The Java environment being used.
  •         The security provider entry.

Read this discussion of what causes “NoSuchProviderException” when you run Java software. (@StackOverflow)

27. AccessControlException

“AccessControlException” indicates that requested access to system resources such as a file system or network is denied, as in this example from JBossDeveloper (@jbossdeveloper):

ERROR Could not register mbeans java.security.

       AccessControlException: WFSM000001: Permission check failed (permission “(“javax.management.MBeanPermission” “org.apache.logging.log4j.core.jmx.LoggerContextAdmin#-

       [org.apache.logging.log4j2:type=51634f]” “registerMBean“)” in code source “(vfs:/C:/wildfly-10.0.0.Final/standalone/deployments/mySampleSecurityApp.war/WEB-INF/lib/log4j-core-2.5.

       jar )” of “null”)

Read this discussion of a workaround used to get past an “AccessControlException” error. (@github)

28. “ArrayStoreException”

An “ArrayStoreException” occurs when the rules of casting elements in Java arrays are broken. Be very careful about what values you place inside an array. (@Roedyg) For instance, this example from JavaScan.com illustrates that this program (@java_scan):

/* …………… START …………… */

public class JavaArrayStoreException {

   public static void main(String… args) {

       Object[] val = new Integer[4];

       val[0] = 5.8;

   }

}

/* …………… END …………… */

Results in the following output:

Exception in thread “main” java.lang.ArrayStoreException: java.lang.Double

       at ExceptionHandling.JavaArrayStoreException.main(JavaArrayStoreException.java:7)

When an array is initialized, the sorts of objects allowed into the array need to be declared. Then each array element needs to be of the same type of object.

Read this discussion of how to solve for the “ArrayStoreException”. (@StackOverflow)

29. “bad magic number”

This Java software error message means something may be wrong with the class definition files on the network. Here’s an example from The Server Side (@TSS_dotcom):

Java(TM) Plug–in: Version 1.3.1_01

       Using JRE version 1.3.1_01 Java HotSpot(TM) Client VM

       User home directory = C:\Documents and Settings\Ankur

       Proxy Configuration: Manual Configuration

       Proxy: 192.168.11.6:80

       java.lang.ClassFormatError: SalesCalculatorAppletBeanInfo (Bad magic number)

       at java.lang.ClassLoader.defineClass0(Native Method)

       at java.lang.ClassLoader.defineClass(Unknown Source)

       at java.security.SecureClassLoader.defineClass(Unknown Source)

       at sun.applet.AppletClassLoader.findClass(Unknown Source)

       at sun.plugin.security.PluginClassLoader.access$201(Unknown Source)

       at sun.plugin.security.PluginClassLoader$1.run(Unknown Source)

       at java.security.AccessController.doPrivileged(Native Method)

       at sun.plugin.security.PluginClassLoader.findClass(Unknown Source)

       at java.lang.ClassLoader.loadClass(Unknown Source)

       at sun.applet.AppletClassLoader.loadClass(Unknown Source)

       at java.lang.ClassLoader.loadClass(Unknown Source)

       at java.beans.Introspector.instantiate(Unknown Source)

       at java.beans.Introspector.findInformant(Unknown Source)

       at java.beans.Introspector.(Unknown Source)

       at java.beans.Introspector.getBeanInfo(Unknown Source)

       at sun.beans.ole.OleBeanInfo.(Unknown Source)

       at sun.beans.ole.StubInformation.getStub(Unknown Source)

       at sun.plugin.ocx.TypeLibManager$1.run(Unknown Source)

       at java.security.AccessController.doPrivileged(Native Method)

       at sun.plugin.ocx.TypeLibManager.getTypeLib(Unknown Source)

       at sun.plugin.ocx.TypeLibManager.getTypeLib(Unknown Source)

       at sun.plugin.ocx.ActiveXAppletViewer.statusNotification(Native Method)

       at sun.plugin.ocx.ActiveXAppletViewer.notifyStatus(Unknown Source)

       at sun.plugin.ocx.ActiveXAppletViewer.showAppletStatus(Unknown Source)

       at sun.applet.AppletPanel.run(Unknown Source)

       at java.lang.Thread.run(Unknown Source)

The “bad magic number” error message happens when:

  • The first four bytes of a class file is not the hexadecimal number CAFEBABE.
  • We upload a  class file in ASCII mode, not binary mode.
  • We tried to run the Java program before compiling it first

Read this discussion of how to find the reason for a “bad magic number”. (@coderanch)

30. “broken pipe”

This error message refers to the data stream from a file or network socket that has stopped working or is closed from the other end (@ExpertsExchange).

Exception in thread “main” java.net.SocketException: Broken pipe

       at java.net.SocketOutputStream.socketWrite0(Native Method)

       at java.net.SocketOutputStream.socketWrite(SocketOutputStream.java:92)

       at java.net.SocketOutputStream.write(SocketOutputStream.java:115)

       at java.io.DataOutputStream.write

The causes of a “broken pipe” error often include:

  •         Running out of disk scratch space.
  •         RAM that is full.
  •         The data stream may be corrupt.
  •         The process of reading the pipe is closed.

Read this discussion of what is the Java error “broken pipe”. (@StackOverflow)

31. “could not create Java Virtual Machine”

This Java error message usually occurs when the code tries to invoke Java with the wrong arguments (@ghacksnews):

Error: Could not create the Java Virtual Machine

       Error: A fatal exception has occurred. Program will exit.

It often is caused by a mistake in the declaration in the code or allocating the proper amount of memory to it.

Read this discussion of how to fix the Java software error “Could not create Java Virtual Machine”. (@StackOverflow)

32. “class file contains wrong class”

The “class file contains wrong class” issue occurs when the Java code tries to find the class file in the wrong directory, resulting in an error message similar to the following:

MyTest.java:10: cannot access MyStruct

       bad class file: D:\Java\test\MyStruct.java

       file does not contain class MyStruct

Please remove or make sure it appears in the correct subdirectory of the classpath.

       MyStruct ms = new MyStruct();

       ^

To fix this error, these tips should help:

  • Make sure the name of the source file and the name of the class match — including the text case.
  • Check if the package statement is correct or missing.
  • Make sure the source file is in the right directory.

Read this discussion of how to fix a “class file contains wrong class” error. (@StackOverflow)

The “ClassCastException” message indicates the Java code is trying to cast an object to the wrong class

33. “ClassCastException”

The “ClassCastException” message indicates the Java code is trying to cast an object to the wrong class. Here is an example from Java Concept of the Day:

package com;

class A

{

   int i = 10;

}

class B extends A

{

   int j = 20;

}

class C extends B

{

   int k = 30;

}

public class ClassCastExceptionDemo

{

   public static void main(String[] args)

   {

       A a = new B();   //B type is auto up casted to A type

       B b = (B) a; //A type is explicitly down casted to B type.

       C c = (C) b;    //Here, you will get class cast exception

       System.out.println(c.k);

   }

}

Results in this error:

Exception in thread “main” java.lang.ClassCastException: com.B cannot be cast to com.C

       at com.ClassCastExceptionDemo.main(ClassCastExceptionDemo.java:23)

The Java code will create a hierarchy of classes and subclasses. To avoid the “ClassCastException” error, make sure the new type belongs to the right class or one of its parent classes. If Generics are used, these errors are are caught when the code is compiled.

Read this tutorial on how to fix “ClassCastException” Java software errors. (@java_concept)

34. “ClassFormatError”

The “ClassFormatError” message indicates a linkage error and occurs when a class file cannot be read or interpreted as a class file.

Caused by: java.lang.ClassFormatError: Absent Code attribute in method that is

       not native or abstract in class file javax/persistence/GenerationType

       at java.lang.ClassLoader.defineClass1(Native Method)

       at java.lang.ClassLoader.defineClassCond(Unknown Source)

       at java.lang.ClassLoader.defineClass(Unknown Source)

       at java.security.SecureClassLoader.defineClass(Unknown Source)

       at java.net.URLClassLoader.defineClass(Unknown Source)

       at java.net.URLClassLoader.access$000(Unknown Source)

       at java.net.URLClassLoader$1.run(Unknown Source)

       at java.security.AccessController.doPrivileged(Native Method)

       at java.net.URLClassLoader.findClass(Unknown Source)

       at java.lang.ClassLoader.loadClass(Unknown Source)

       at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)

       at java.lang.ClassLoader.loadClass(Unknown Source)

There are several reasons why a “ClassFormatError” can occur:

  • We uploaded a class file in ASCII mode not binary mode.
  • The web server must send class files as binary, not ASCII.
  • There could be a classpath error that prevents the code from finding the class file.
  • Loading the same class twice throws an exception
  • You’re using an old version of Java runtime.

Read this discussion about what causes the “ClassFormatError” in Java. (@StackOverflow)

35. “ClassNotFoundException”

“ClassNotFoundException” only occurs at run time — meaning a class that was there during compilation is missing at run time. This is a linkage error.

Much like the “NoClassDefFoundError” this issue can occur if:

  • The file is not in the right directory.
  • The name of the class is not the same as the name of the file (without the file extension). Also, the names are case-sensitive.

Read this discussion of what causes “ClassNotFoundException” for more cases. (@StackOverflow)

36. “ExceptionInInitializerError”

This Java issue will occur when something goes wrong with a static initialization (@GitHub). When the Java code later uses the class, the “NoClassDefFoundError” error will occur.

java.lang.ExceptionInInitializerError

       at org.eclipse.mat.hprof.HprofIndexBuilder.fill(HprofIndexBuilder.java:54)

       at org.eclipse.mat.parser.internal.SnapshotFactory.parse(SnapshotFactory.java:193)

       at org.eclipse.mat.parser.internal.SnapshotFactory.openSnapshot(SnapshotFactory.java:106)

       at com.squareup.leakcanary.HeapAnalyzer.openSnapshot(HeapAnalyzer.java:134)

       at com.squareup.leakcanary.HeapAnalyzer.checkForLeak(HeapAnalyzer.java:87)

       at com.squareup.leakcanary.internal.HeapAnalyzerService.onHandleIntent(HeapAnalyzerService.java:56)

       at android.app.IntentService$ServiceHandler.handleMessage(IntentService.java:65)

       at android.os.Handler.dispatchMessage(Handler.java:102)

       at android.os.Looper.loop(Looper.java:145)

       at android.os.HandlerThread.run(HandlerThread.java:61)

       Caused by: java.lang.NullPointerException: in == null

       at java.util.Properties.load(Properties.java:246)

       at org.eclipse.mat.util.MessageUtil.(MessageUtil.java:28)

       at org.eclipse.mat.util.MessageUtil.(MessageUtil.java:13)

       … 10 more

There needs to be more information to fix the error. Using getCause() in the code can return the exception that caused the error to be returned.

Read this discussion about how to track down the cause of the “ExceptionInInitializerError”. (@StackOverflow)

37. “IllegalBlockSizeException”

An “IllegalBlockSizeException” will occur during decryption when the length message is not a multiple of 8 bytes. Here’s an example from ProgramCreek.com (@ProgramCreek):

@Override

protected byte[] engineWrap(Key key) throws IllegalBlockSizeException, InvalidKeyException {

       try {

       byte[] encoded = key.getEncoded();

       return engineDoFinal(encoded, 0, encoded.length);

       } catch (BadPaddingException e) {

       IllegalBlockSizeException newE = new IllegalBlockSizeException();

       newE.initCause(e);

       throw newE;

       }

       }

The causes for the “IllegalBlockSizeException” can be:

  • Using different encryption and decryption algorithm options.
  • Truncating or garbling the decrypted message during transmission.

Read this discussion about how to prevent the “IllegalBlockSizeException” Java software error message. (@StackOverflow)

38. “BadPaddingException”

A “BadPaddingException” will occur during decryption when padding was used to create a message that can be measured by a multiple of 8 bytes. Here’s an example from Stack Overflow (@StackOverflow):

javax.crypto.BadPaddingException: Given final block not properly padded

       at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)

       at com.sun.crypto.provider.SunJCE_f.b(DashoA13*..)

       at com.sun.crypto.provider.AESCipher.engineDoFinal(DashoA13*..)

       at javax.crypto.Cipher.doFinal(DashoA13*..)

Encrypted data is binary so don’t try to store it in a string or the data will not be padded properly during encryption.

Read this discussion about how to prevent the “BadPaddingException”. (@StackOverflow)

39. “IncompatibleClassChangeError”

An “IncompatibleClassChangeError” is a form of LinkageError that can occur when a base class changes after the compilation of a child class. This example is from How to Do in Java (@HowToDoInJava):

Exception in thread “main” java.lang.IncompatibleClassChangeError: Implementing class

at java.lang.ClassLoader.defineClass1(Native Method)

       at java.lang.ClassLoader.defineClass(Unknown Source)

       at java.security.SecureClassLoader.defineClass(Unknown Source)

       at java.net.URLClassLoader.defineClass(Unknown Source)

       at java.net.URLClassLoader.access$000(Unknown Source)

       at java.net.URLClassLoader$1.run(Unknown Source)

       at java.security.AccessController.doPrivileged(Native Method)

       at java.net.URLClassLoader.findClass(Unknown Source)

       at java.lang.ClassLoader.loadClass(Unknown Source)

       at sun.misc.Launcher$AppClassLoader.loadClass(Unknown Source)

       at java.lang.ClassLoader.loadClass(Unknown Source)

       at java.lang.ClassLoader.loadClassInternal(Unknown Source)

       at net.sf.cglib.core.DebuggingClassWriter.toByteArray(DebuggingClassWriter.java:73)

       at net.sf.cglib.core.DefaultGeneratorStrategy.generate(DefaultGeneratorStrategy.java:26)

       at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:216)

       at net.sf.cglib.core.KeyFactory$Generator.create(KeyFactory.java:144)

       at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:116)

       at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:108)

       at net.sf.cglib.core.KeyFactory.create(KeyFactory.java:104)

       at net.sf.cglib.proxy.Enhancer.(Enhancer.java:69)

When the “IncompatibleClassChangeError” occurs, it is possible that:

  • We forgot the word “static” on the main method.
  • A legal class was used illegally.
  • A class was changed and there are references to it from another class by its old signatures.

Try deleting all class files and recompiling everything, or try these steps to resolve the “IncompatibleClassChangeError”. (@javacodegeeks)

40. “FileNotFoundException”

This Java software error message is when a file with the specified pathname does not exist.

@Override public ParcelFileDescriptor openFile(Uri uri,String mode) throws FileNotFoundException {

       if (uri.toString().startsWith(FILE_PROVIDER_PREFIX)) {

       int m=ParcelFileDescriptor.MODE_READ_ONLY;

       if (mode.equalsIgnoreCase(“rw”)) m=ParcelFileDescriptor.MODE_READ_WRITE;

       File f=new File(uri.getPath());

       ParcelFileDescriptor pfd=ParcelFileDescriptor.open(f,m);

       return pfd;

       }

       else {

       throw new FileNotFoundException(“Unsupported uri: “ + uri.toString());

       }

       }


In addition to files not exhibiting the specified pathname, this could mean the existing file is inaccessible.

Read this discussion about the “FileNotFoundException”. (@StackOverflow)

41. “EOFException”

An “EOFException” is thrown when an end of file or end of the stream has been reached unexpectedly during input. Here’s an example from JavaBeat of an application that throws an EOFException:

import java.io.DataInputStream;

import java.io.EOFException;

import java.io.File;

import java.io.FileInputStream;

import java.io.IOException;

public class ExceptionExample {

   public void testMethod1(){

       File file = new File(“test.txt”);

       DataInputStream dataInputStream =  null;

       try{

           dataInputStream = new DataInputStream(new FileInputStream(file));

           while(true){

               dataInputStream.readInt();

           }

       }catch (EOFException e){

           e.printStackTrace();

       }

       catch (IOException e){

           e.printStackTrace();

       }

       finally{

           try{

               if (dataInputStream != null){

                   dataInputStream.close();

               }

           }catch (IOException e){

               e.printStackTrace();

           }

       }

   }

   public static void main(String[] args){

       ExceptionExample instance1 = new ExceptionExample();

       instance1.testMethod1();

   }

}

Running the program above results in the following exception:

java.io.EOFException

       at java.io.DataInputStream.readInt(DataInputStream.java:392)

       at logging.simple.ExceptionExample.testMethod1(ExceptionExample.java:16)

       at logging.simple.ExceptionExample.main(ExceptionExample.java:36)

When there is no more data while the class “DataInputStream” is trying to read data in the stream, “EOFException” will be thrown. It can also occur in the “ObjectInputStream” and “RandomAccessFile” classes.

Read this discussion about when the “EOFException” can occur while running Java software. (@StackOverflow)

42. “UnsupportedEncodingException”

This Java software error message is thrown when the character encoding is not supported (@Penn).

public UnsupportedEncodingException()

It is possible that the Java Virtual Machine being used doesn’t support a given character set.

Read this discussion of how to handle “UnsupportedEncodingException” while running Java software. (@StackOverflow)

43. “SocketException”

A “SocketException” message indicates there is an error creating or accessing a socket (@ProgramCreek).

public void init(String contextName, ContextFactory factory) {

       super.init(contextName, factory);

       String periodStr = getAttribute(PERIOD_PROPERTY);

       if (periodStr != null) {

       int period = 0;

       try {

       period = Integer.parseInt(periodStr);

       } catch (NumberFormatException nfe) {

       }

       if (period <= 0) {

       throw new MetricsException(“Invalid period: “ + periodStr);

       }

       setPeriod(period);

       }




       metricsServers =

       Util.parse(getAttribute(SERVERS_PROPERTY), DEFAULT_PORT);

       unitsTable = getAttributeTable(UNITS_PROPERTY);

       slopeTable = getAttributeTable(SLOPE_PROPERTY);

       tmaxTable  = getAttributeTable(TMAX_PROPERTY);

       dmaxTable  = getAttributeTable(DMAX_PROPERTY);




       try {

       datagramSocket = new DatagramSocket();

       }

       catch (SocketException se) {

       se.printStackTrace();

       }

       }

We encounter this exception when the we reach the maximum number of connection. This can happen due to:

  • No more network ports available to the application.
  • The system doesn’t have enough memory to support new connections.

Read this discussion of how to resolve “SocketException” issues while running Java software. (@StackOverflow)

This Java software error message occurs when there is a failure in SSL-related operations

44. “SSLException”

This Java software errors message occurs when there is a failure in SSL-related operations. The following example is from Atlassian (@Atlassian):

com.sun.jersey.api.client.ClientHandlerException: javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non–empty

       at com.sun.jersey.client.apache.ApacheHttpClientHandler.handle(ApacheHttpClientHandler.java:202)

       at com.sun.jersey.api.client.Client.handle(Client.java:365)

       at com.sun.jersey.api.client.WebResource.handle(WebResource.java:556)

       at com.sun.jersey.api.client.WebResource.get(WebResource.java:178)

       at com.atlassian.plugins.client.service.product.ProductServiceClientImpl.getProductVersionsAfterVersion(ProductServiceClientImpl.java:82)

       at com.atlassian.upm.pac.PacClientImpl.getProductUpgrades(PacClientImpl.java:111)

       at com.atlassian.upm.rest.resources.ProductUpgradesResource.get(ProductUpgradesResource.java:39)

       at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

       at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)

       at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

       at java.lang.reflect.Method.invoke(Unknown Source)

       at com.atlassian.plugins.rest.common.interceptor.impl.DispatchProviderHelper$ResponseOutInvoker$1.invoke(DispatchProviderHelper.java:206)

       at com.atlassian.plugins.rest.common.interceptor.impl.DispatchProviderHelper$1.intercept(DispatchProviderHelper.java:90)

       at com.atlassian.plugins.rest.common.interceptor.impl.DefaultMethodInvocation.invoke(DefaultMethodInvocation.java:61)

       at com.atlassian.plugins.rest.common.expand.interceptor.ExpandInterceptor.intercept(ExpandInterceptor.java:38)

       at com.atlassian.plugins.rest.common.interceptor.impl.DefaultMethodInvocation.invoke(DefaultMethodInvocation.java:61)

       at com.atlassian.plugins.rest.common.interceptor.impl.DispatchProviderHelper.invokeMethodWithInterceptors(DispatchProviderHelper.java:98)

       at com.atlassian.plugins.rest.common.interceptor.impl.DispatchProviderHelper.access$100(DispatchProviderHelper.java:28)

       at com.atlassian.plugins.rest.common.interceptor.impl.DispatchProviderHelper$ResponseOutInvoker._dispatch(DispatchProviderHelper.java:202)

       …

       Caused by: javax.net.ssl.SSLException: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non–empty

       …

       Caused by: java.lang.RuntimeException: Unexpected error: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non–empty

       …

       Caused by: java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non–empty

This can happen if:

  • Certificates on the server or client have expired.
  • A server port changed

Read this discussion of what can cause the “SSLException” error in Java software. (@StackOverflow)

45. “MissingResourceException”

A “MissingResourceException” occurs when a resource is missing. If the resource is in the correct classpath, this is usually because a properties file is not configured properly. Here’s an example (@TIBCO):

java.util.MissingResourceException: Can‘t find bundle for base name localemsgs_en_US, locale en_US

       java.util.ResourceBundle.throwMissingResourceException

       java.util.ResourceBundle.getBundleImpl

       java.util.ResourceBundle.getBundle

       net.sf.jasperreports.engine.util.JRResourcesUtil.loadResourceBundle

       net.sf.jasperreports.engine.util.JRResourcesUtil.loadResourceBundle

Read this discussion of how to fix “MissingResourceException” while running Java software.

46. “NoInitialContextException”

A “NoInitialContextException” error occurs when the Java application wants to perform a naming operation but can’t create a connection (@TheASF).

[java] Caused by: javax.naming.NoInitialContextException: Need to specify class name in environment or system property, or as an applet parameter, or in an application resource file:  java.naming.factory.initial

       [java] at javax.naming.spi.NamingManager.getInitialContext(NamingManager.java:645)

       [java] at javax.naming.InitialContext.getDefaultInitCtx(InitialContext.java:247)

       [java] at javax.naming.InitialContext.getURLOrDefaultInitCtx(InitialContext.java:284)

       [java] at javax.naming.InitialContext.lookup(InitialContext.java:351)

       [java] at org.apache.camel.impl.JndiRegistry.lookup(JndiRegistry.java:51)

This can be a complex problem to solve but here are some possible issues that cause the “NoInitialContextException” Java software errors message:

  • The application may not have the proper credentials to make a connection.
  • The code may not identify the implementation of JNDI needed.
  • The “InitialContext” class configuration doesn’t contain the right properties.

Read this discussion of what “NoInitialContextException” means when running Java software. (@StackOverflow)

47. “NoSuchElementException”

A “NoSuchElementException” error happens when an iteration (such as a “for” loop) tries to access the next element when there is none.

public class NoSuchElementExceptionDemo{

   public static void main(String args[]) {

       Hashtable sampleMap = new Hashtable();

       Enumeration enumeration = sampleMap.elements();

       enumeration.nextElement();  //java.util.NoSuchElementExcepiton here because enumeration is empty

   }

}

Output:

Exception in thread “main” java.util.NoSuchElementException: Hashtable Enumerator

       at java.util.Hashtable$EmptyEnumerator.nextElement(Hashtable.java:1084)

       at test.ExceptionTest.main(NoSuchElementExceptionDemo.java:23)

These methods throw the “NoSuchElementException”:

  • Enumeration::nextElement()
  • NamingEnumeration::next()
  • StringTokenizer::nextElement()
  • Iterator::next()

Read this tutorial on how to fix “NoSuchElementException” in Java software. (@javinpaul)

48. “NoSuchFieldError”

This Java software errors message is thrown when an application tries to access a field in an object but the specified field no longer exists in the object (@sourceforge).

public NoSuchFieldError()

Usually, the compiler catches this error. However, it will be caught during runtime if a class definition has been changed between compiling and running.

Read this discussion of how to find what causes the “NoSuchFieldError” when running Java software. @StackOverflow

49. “NumberFormatException”

This Java software error message occurs when the application tries to convert a string to a numeric type, but that the number is not a valid string of digits (@alvinalexander).

package com.devdaily.javasamples;

public class ConvertStringToNumber {

   public static void main(String[] args) {

       try {

           String s = “FOOBAR”;

           int i = Integer.parseInt(s);

           // this line of code will never be reached

           System.out.println(“int value = “ + i);

       }

       catch (NumberFormatException nfe) {

           nfe.printStackTrace();

       }

   }

}


The compiler throws the error “NumberFormatException” when:

  • Leading or trailing spaces in the number exist.
  • The sign is not ahead of the number.
  • The number has commas.
  • Localisation may not categorize it as a valid number.
  • The number is too big to fit in the numeric type.

Read this discussion of how to avoid “NumberFormatException” when running Java software. (@StackOverflow)

50. “TimeoutException”

This Java software errors message occurs when a blocking operation runs for too long ands results in a timeout.

private void queueObject(ComplexDataObject obj) throws TimeoutException, InterruptedException {

       if (!queue.offer(obj,10,TimeUnit.SECONDS)) {

       TimeoutException ex=new TimeoutException(“Timed out waiting for parsed elements to be processed. Aborting.”);

       throw ex;

       }

       }

Read this discussion about how to handle “TimeoutException” when running Java software. (@StackOverflow)

For the ultimate Java developer’s toolkit, don’t forget to download The Comprehensive Java Developer’s Guide.

The fastest way to fix errors in your software is to properly implement an error monitoring system, such as Retrace

Retrace Error Monitoring

The fastest way to fix errors in your software is to properly implement an error monitoring system, such as Retrace.

With Retrace, you can find hidden java software errors lying silently in your code. Its powerful and efficient code profiling even tracks the java software errors you aren’t logging and helps you monitor error spikes and fix them quickly before reaching your users. Not only that, you will know when there are new types of java software errors within your application because the system will notify you through an email or SMS.

Also available to help you write error-free code with ease is Stackify by Netreo’s free code profiler, Prefix, which supports .NET, Java, PHP, Node.js, Ruby, and Python applications.

For more tips and tricks for coding better Java programs, download our Comprehensive Java Developer’s Guide, which is full with everything you need to up your Java game – from tools to the best websites and blogs, YouTube channels, Twitter influencers, LinkedIn groups, podcasts, must-attend events, and more.

If you’re working with .NET, you should also check out our guide to the 50 most common .NET software errors and how to avoid them.

There is no better time than now. Start your 14-day FREE TRIAL and experience the advantage of Retrace and Prefix from Stackify by Netreo.

]]>
ViewBag 101: How It Works, When It’s Used, Code Examples, and More https://stackify.com/refresh-viewbag-101-how-it-works-when-its-used-code-examples-and-more/ Thu, 12 Oct 2023 17:14:28 +0000 https://stackify.com/?p=42343 ViewBag is a property – considered a dynamic object – that enables you to share values dynamically between the controller and view within ASP.NET MVC applications. Let’s take a closer look at ViewBag, when it’s used, some limitations and other possible options to consider.

Ways to Pass Data from the Controller to the View

In the case of ASP.NET MVC, you have three ways to pass data from the controller to the view. These are:

  1. ViewBag
  2. ViewData
  3. TempData

ViewBag and ViewData are highly similar in the way they pass data from controller to view, and both are considered as a way to communicate between the view and the controller within a server call. Both of these objects work well when you use external data.

How does one differ from the other? 

ViewData is a dictionary or listing of objects that you can use to put data into. The data is now accessible to view. It is based on the ViewDataDictionary class. You can use ViewBag around any ViewData object so that you could assign dynamic properties to it, making it more flexible.

You would need typecasting for ViewData and check for null values, but you do not need to typecast complex data types in ViewBag.

The Microsoft Developer Network writes that the ViewBag property allows you to share values dynamically to the view from the controller

What is ViewBag?

The Microsoft Developer Network writes that the ViewBag property allows you to share values dynamically to the view from the controller. As such, ViewBag is considered a dynamic object without pre-set properties.

The syntax for using it in C# is:

public object ViewBag { get; }

For C++:

public:
property Object^ ViewBag {
	Object^ get();
}

Syntax For F#:

public object ViewBag { get; }

For VB:

Public ReadOnly Property ViewBag As Object

You can define the properties that you want by adding them, and you would need to use the same property name if you want to retrieve these values in view.

Here is a nifty example for that. In the controller, you can set up properties such as:

public ActionResult Index() //We'll set the ViewBag values in this action
{
ViewBag.Title = "Put your page title here";
ViewBag.Description = "Put your page description here";

ViewBag.UserNow = new User()
{
   Name = "Your Name",
   ID = 4,
};

return View();

}

To display these properties in view, you would need to use the same property names.

<h3>@ViewBag.Title</h3>

<p>@ViewBag.Description</p>

Your name:

<div>
<dl>
<dt>Name:</dt>
<dd>@ViewBag.UserNow.Name</dd>
<dt>ID:</dt>
<dd>@ViewBag.CurrentUser.ID</dd>
</dl>
</div>

A step-by-step demonstration is available at C# Corner.

When is It Used?

ViewBag is used to allow you to share values dynamically. There are several variables that are not known before the program is run, and these values are only entered during runtime. And this is where ViewBag shines, because you can put just about anything you want into it.

You can use ViewBag objects for transferring small amounts of data from the controller to the view, in cases such as:

  • Shopping carts
  • Dropdown lists options
  • Widgets
  • Aggregated data

ViewBag is a great way to access data that you use but may reside outside the data model. ViewBag is easy to use, because it’s implemented as a property of both controllers and view.

There is also one instance when ViewBag is mandatory, and that is when you are specifying a page title on any given view. For instance:

@{

ViewBag.PageTitle = "Page title will be displayed on the browser tab";

}

Some Limitations

As you may have guessed, ViewBag is not suitable for bigger sets of data or more complicated ones. For instance, complex relational data, big sets of aggregate data, data coming from a variety of sources and dashboards.

Also, there are some potential problems you may encounter. Errors, for instance, are not detected during compilation. Because of ViewBag’s dynamic nature, you can create names according to your liking. Dynamic properties are not checked during compilation, unlike normal types. What does this mean? You may not be able to detect if you used the right name and whether it matches the name you specified in the view.

For instance, you have assigned the following properties:

public ActionResult Index() //We'll set the ViewBag values in this action

{

ViewBag.Titl = "Enter your title here";

return View();

}

Then use this code for the view:

<h3>@ViewBag.Title</h3>

In this example, you specified Title as a ViewBag name, and this is a valid variable name for the property. But the view is looking for the variable name “Title.” When you compile your program, you would not be alerted to this error. Imagine having a lot of names to check manually!

ViewBag vs. TempData

TempData, on the other hand, is also a dictionary based on the TempDataDictionary class. TempData keeps information temporarily, as long as the HTTP request is active, and is perfect for redirects and a few other instances because of its temporary nature.

ViewModel

As discussed in the limitations section, there are several types of data where you cannot use ViewBag, primarily those big and complex data sets. For these types of data, you can use ViewModel if you are using ASP.NET MVC.

ViewModel also has a distinct advantage in that it is strongly typed. This means that unlike in ViewBag, ViewModel does not confuse one type with another type. For example, using ViewBag, the compiler will not detect an error when you use a DateTime as if it were a string.

public ActionResult Index() //We'll set the ViewBag values in this action
{
ViewBag.PageCreationDate = DateTime.Now;
ViewBag.LastIndexOfP = ViewBag.PageCreateDate.LastIndexOf('p');
return View();
}

The ViewBag property, LastIndexOfP in this case, is trying to get ‘p’ based on the PageCreationDate. In this example, you are treating a DateTime as a string, and compiling your program would not detect that error. Using ViewModel, you have better type protection, and error such as this one is detected by the compiler.

In general, ViewBag is a way to pass data from the controller to the view. It is a type object and is a dynamic property under the controller base class

Summary

In general, ViewBag is a way to pass data from the controller to the view. It is a type object and is a dynamic property under the controller base class. Compared to ViewData, it works similarly but is known to be a bit slower and was introduced in ASP.NET MVC 3.0 (ViewData was introduced in MVC 1.0).

The use of ViewBag has some limitations in that the compiler cannot check dynamic types and you would need to run your program first to find the errors when you use it. As such, using ViewModel is highly recommended in some instances.

ViewBag is a way to pass data from the controller to the view, but it does have a few limitations. You can build better when you understand ViewBag, when to use it, and what other options are available that may be better suited for certain use cases – such as ViewData (which is a bit faster) and ViewModel (when you need to check dynamic types).

If you want to write better ASP.NET applications, Stackify’s Prefix is a lightweight ASP.NET profiler that can help you write better software. And, if you want to take it up a notch, our APM tool offers the best in ASP.NET application monitoring. Check out our other tutorials for doing more with ASP.NET, such as understanding ASP.NET performance for reading incoming data, and find out what we learned while converting from ASP.NET to .NET Core in this post.

Additional Resources and Tutorials

For more information, check out the following resources and tutorials:

]]>
Python Garbage Collection: What It Is and How It Works https://stackify.com/python-garbage-collection/ Thu, 21 Sep 2023 11:41:48 +0000 https://stackify.com/?p=24081 Python is one of the most popular programming languages and its usage continues to grow. It ranked first in the TIOBE language of the year in 2022 and 2023 due to its growth rate. Python’s ease of use and large community have made it a popular fit for data analysis, web applications, and task automation.

In this post, we’ll cover:

  • Basics of Memory Management
  • Why we need Garbage Collection
  • How Python Implements Garbage Collection

We’ll take a practical look at how you should think about garbage collection when writing your Python applications.

What is Python garbage collection and why do we need It?

If Python is your first programming language, the whole idea of garbage collection might be foreign to you. Let’s start with the basics.

Memory management

A programming language uses objects in its programs to perform operations. Objects include simple variables, like strings, integers, or booleans. They also include more complex data structures like lists, hashes, or classes.

The values of your program’s objects are stored in memory for quick access. In many programming languages, a variable in your program code is simply a pointer to the address of the object in memory. When a variable is used in a program, the process will read the value from memory and operate on it.

In early programming languages, most developers were responsible for all memory management in their programs. This meant before creating a list or an object, you first needed to allocate the memory for your variable. After you were done with your variable, you then needed to deallocate it to “free” that memory for other users.

This led to two problems:

  1. Forgetting to free your memory. If you don’t free your memory when you’re done using it, it can result in memory leaks. This can lead to your program using too much memory over time. For long-running applications, this can cause serious problems.
  2. Freeing your memory too soon. The second type of problem consists of freeing your memory while it’s still in use. This can cause your program to crash if it tries to access a value in memory that doesn’t exist, or it can corrupt your data. A variable that refers to memory that has been freed is called a dangling pointer.

These problems were undesirable, and so some newer languages added automatic memory management.

Automatic memory management and garbage collection

With automatic memory management, programmers no longer needed to manage memory themselves. Rather, the runtime handled this for them.

There are a few different methods for automatic memory management. The popular ones use reference counting. With reference counting, the runtime keeps track of all of the references to an object. When an object has zero references to it, it’s unusable by the program code and can be deleted.

For programmers, automatic memory management adds a number of benefits. It’s faster to develop programs without thinking about low-level memory details. Further, it can help avoid costly memory leaks or dangerous dangling pointers.

However, automatic memory management comes at a cost. Your program will need to use additional memory and computation to track all of its references. What’s more, many programming languages with automatic memory management use a “stop-the-world” process for garbage collection where all execution stops while the garbage collector looks for and deletes objects to be collected.

With the advances in computer processing from Moore’s law and the larger amounts of RAM in newer computers, the benefits of automatic memory management usually outweigh the downsides. Thus, most modern programming languages like Java, Python, and Golang use automatic memory management.

For long-running applications where performance is critical, some languages still have manual memory management. The classic example of this is C++. We also see manual memory management in Objective-C, the language used for macOS and iOS. For newer languages, Rust uses manual memory management.

Now that we know about memory management and garbage collection in general, let’s get more specific about how Python garbage collection works.

Try Stackify’s free code profiler, Prefix, to write better code on your workstation. Prefix works with .NET, Java, PHP, Node.js, Ruby, and Python.

How Python implements garbage collection

In this section, we’ll cover how garbage collection works in Python.

This section assumes you’re using the CPython implementation of Python. CPython is the most widely used implementation. However, there are other implementations of Python, such as PyPyJython (Java-based), or IronPython (C#-based).

To see which Python you’re using, run the following command in your terminal (Linux):

>>>python -c 'import platform; print(platform.python_implementation())'

Or, you can have these lines for both Linux and Windows terminals.
>>> import platform
>>> print(platform.python_implementation())
CPython

There are two aspects to memory management and garbage collection in CPython:

  • Reference counting
  • Generational garbage collection

Let’s explore each of these below. 

Reference counting in CPython

The main garbage collection mechanism in CPython is through reference counts. Whenever you create an object in Python, the underlying C object has both a Python type (such as list, dict, or function) and a reference count.

At a very basic level, a Python object’s reference count is incremented whenever the object is referenced, and it’s decremented when an object is dereferenced. If an object’s reference count is 0, the memory for the object is deallocated.

Your program’s code can’t disable Python’s reference counting. This is in contrast to the generational garbage collector discussed below.

Some people claim reference counting is a poor man’s garbage collector. It does have some downsides, including an inability to detect cyclic references as discussed below. However, reference counting is nice because you can immediately remove an object when it has no references.

Viewing reference counts in Python

You can use the sys module from the Python standard library to check reference counts for a particular object. There are a few ways to increase the reference count for an object, such as 

  • Assigning an object to a variable.
  • Adding an object to a data structure, such as appending to a list or adding as a property on a class instance.
  • Passing the object as an argument to a function.

Let’s use a Python REPL and the sys module to see how reference counts are handled.

First, in your terminal, type python to enter into a Python REPL.

Second, import the sys module into your REPL. Then, create a variable and check its reference count:

>>> import sys
>>> a = 'my-string'
>>> sys.getrefcount(a)
2

Notice that there are two references to our variable a. One is from creating the variable. The second is when we pass the variable a to the sys.getrefcount() function.

If you add the variable to a data structure, such as a list or a dictionary, you’ll see the reference count increase:

>>> import sys
>>> a = 'my-string'
>>> b = [a] # Make a list with a as an element.
>>> c = { 'key': a } # Create a dictionary with a as one of the values.
>>> sys.getrefcount(a)
4

As shown above, the reference count of a increases when added to a list or a dictionary.

In the next section, we’ll learn about the generational garbage collector, which is the second tool Python uses for memory management.

Generational garbage collection

In addition to the reference counting strategy for memory management, Python also uses a method called a generational garbage collector.

The easiest way to understand why we need a generational garbage collector is by way of example.

In the previous section, we saw that adding an object to an array or object increased its reference count. But what happens if you add an object to itself?

>>> class MyClass(object):
...     pass
...
>>> a = MyClass()
>>> a.obj = a
>>> del a

In the example above, we defined a new class. We then created an instance of the class and assigned the instance to be a property on itself. Finally, we deleted the instance.

By deleting the instance, it’s no longer accessible in our Python program. However, Python didn’t destroy the instance from memory. The instance doesn’t have a reference count of zero because it has a reference to itself.

We call this type of problem a reference cycle, and you can’t solve it by reference counting. This is the point of the generational garbage collector, which is accessible by the gc module in the standard library.

Generational garbage collector terminology

There are two key concepts to understand with the generational garbage collector.

  1. The first concept is that of a generation.
  2. The second key concept is the threshold.

The garbage collector is keeping track of all objects in memory. A new object starts its life in the first generation of the garbage collector. If Python executes a garbage collection process on a generation and an object survives, it moves up into a second, older generation. The Python garbage collector has three generations in total, and an object moves into an older generation whenever it survives a garbage collection process on its current generation.

For each generation, the garbage collector module has a threshold number of objects. If the number of objects exceeds that threshold, the garbage collector will trigger a collection process. For any objects that survive that process, they’re moved into an older generation.

Unlike the reference counting mechanism, you may change the behavior of the generational garbage collector in your Python program. This includes changing the thresholds for triggering a garbage collection process in your code. Additionally, you can manually trigger a garbage collection process, or disable the garbage collection process altogether.

Let’s see how you can use the gc module to check garbage collection statistics or change the behavior of the garbage collector.

Using the GC module

In your terminal, enter python to drop into a Python REPL.

Import the gc module into your session. You can then check the configured thresholds of your garbage collector with the get_threshold() method:

>>> import gc
>>> gc.get_threshold()
(700, 10, 10)

By default, Python has a threshold of 700 for the youngest generation and 10 for each of the two older generations.

You can check the number of objects in each of your generations with the get_count() method:

>>> import gc
>>> gc.get_count()
(596, 2, 1)

In this example, we have 596 objects in our youngest generation, two objects in the next generation, and one object in the oldest generation.

As you can see, Python creates a number of objects by default before you even start executing your program. You can trigger a manual garbage collection process by using the gc.collect() method:

>>> gc.get_count()
(595, 2, 1)
>>> gc.collect()
577
>>> gc.get_count()
(18, 0, 0)

Running a garbage collection process cleans up a huge amount of objects—there are 577 objects in the first generation and three more in the older generations.

You can alter the thresholds for triggering garbage collection by using the set_threshold() method in the gc module:

>>> import gc
>>> gc.get_threshold()
(700, 10, 10)
>>> gc.set_threshold(1000, 15, 15)
>>> gc.get_threshold()
(1000, 15, 15)

In the example above, we increase each of our thresholds from their defaults. Increasing the threshold will reduce the frequency at which the garbage collector runs. This will be less computationally expensive in your program at the expense of keeping dead objects around longer.

Now that you know how both reference counting and the garbage collector module work, let’s discuss how you should use this when writing Python applications.

Python Garbage Collector

What does Python’s garbage collector mean for you as a developer

We’ve spent a fair bit of time discussing memory management generally and its implementation in Python. Now it’s time to make it useful. How should you use this information as a developer of Python programs?

General rule: Don’t change garbage collector behavior

As a general rule, you probably shouldn’t think about Python’s garbage collection too much. One of the key benefits of Python is it enables developer productivity. Part of the reason for this is because it’s a high-level language that handles a number of low-level details for the developer.

Manual memory management is more relevant for constrained environments. If you do find yourself with performance limitations that you think may be related to Python’s garbage collection mechanisms, it will probably be more useful to increase the power of your execution environment rather than to manually alter the garbage collection process. In a world of Moore’s law, cloud computing, and cheap memory, more power is readily accessible.

This is even realistic given that Python generally doesn’t release memory back to the underlying operating system. Any manual garbage collection process you do to free memory may not give you the results you want. For more details in this area, refer to this post on memory management in Python.

Disabling the garbage collector

With that caveat aside, there are situations where you may want to manage the garbage collection process. Remember that reference counting, the main garbage collection mechanism in Python, can’t be disabled. The only garbage collection behavior you can alter is the generational garbage collector in the gc module.

One of the more interesting examples of altering the generational garbage collector came from Instagram disabling the garbage collector altogether.

Instagram uses Django, the popular Python web framework, for its web applications. It runs multiple instances of its web application on a single compute instance. These instances are run using a master-child mechanism where the child processes share memory with the master.

The Instagram dev team noticed that the shared memory would drop sharply soon after a child process spawned. When digging further, they saw that the garbage collector was to blame.

The Instagram team disabled the garbage collector module by setting the thresholds for all generations to zero. This change led to their web applications running 10% more efficiently.

While this example is interesting, make sure you’re in a similar situation before following the same path. Instagram is a web-scale application serving many millions of users. To them, it’s worth it to use some non-standard behavior to squeeze every inch of performance from their web applications. For most developers, Python’s standard behavior around garbage collection is sufficient.

If you think you may want to manually manage garbage collection in Python, make sure you understand the problem first. Use tools like Stackify’s Retrace to measure your application performance and pinpoint issues. Once you fully understand the problem, then take steps to fix it.

Start your 14-day FREE trial today!

Retrace Python APM

Wrapping up

In this post, we learned about Python garbage collection. We started by covering the basics of memory management and the creation of automatic memory management. We then looked at how garbage collection is implemented in Python, through both automatic reference counting and a generational garbage collector. Finally, we reviewed how this matters to you as a Python developer.

While Python handles most of the hard parts of memory management for you, it’s still helpful to know what’s happening under the hood. From reading this post, you now know that you should avoid reference cycles in Python, and you should know where to look if you need greater control over Python garbage collector.

]]>
How to Rescue Exceptions in Ruby https://stackify.com/rescue-exceptions-ruby/ Thu, 21 Sep 2023 11:25:01 +0000 https://stackify.com/?p=23441 Exceptions are a commonly used feature in the Ruby programming language. The Ruby standard library defines about 30 different subclasses of exceptions, some of which have their own subclasses. The exception mechanism in Ruby is very powerful but often misused. This article will discuss the use of exceptions and show some examples of how to deal with them.

What is an exception?

An exception represents an error condition in a program. Exceptions provide a mechanism for stopping the execution of a program. They function similarly to “break,” in that they cause the instruction pointer to jump to another location. Unlike break, the location may be another layer of the program stack. Unhandled exceptions cause Ruby programs to stop.

When to handle an exception

A simple rule for handling exceptions is to handle only those exceptions you can do something about. That’s easy to say, but sometimes difficult to get right. We have a tendency to want to rescue every exception that could possibly occur. Because we often don’t know what to do about an exception, we tend to just log a message and continue execution. Often this leads to writing extra code to deal with the failures—code we don’t actually need.

We should handle exceptions only when we can reasonably take some action to correct the error and allow our program to continue functioning.

We need to think about three basic categories of exceptional behavior when writing code: possible, probable, and inevitable.

Possible exceptions

Possible exceptions are theoretically possible, but unlikely to occur in the system. When these kinds of exceptions occur, it’s typically because the system is truly broken. In this case, the situation is irrecoverable, and we shouldn’t try to handle the exceptions.

Probable exceptions

Probable exceptions may reasonably happen during our program’s execution—for example, a REST call failure caused by a DNS issue. These are the issues we can foresee when developing our program, and in some cases, we can see a resolution to these problems. This is where we should focus the bulk of our exception handling attention.

Inevitable exceptions

Inevitable exceptions will happen quite often. A common tendency is to allow these exceptions. A more effective approach is to proactively detect the exceptional condition and branch around it. Exceptions shouldn’t be used for flow control. Wherever possible, if we can predetermine that an operation would create an exceptional condition, we shouldn’t execute the operation.

When exceptions occur

Take a corrective action whenever an exception occurs. That is, exception handling is about civilizing the behavior of our programs. You should not bury the exceptions—begin, rescue, bury are anti-patterns that should be avoided.

That said, sometimes the only thing we can do is report that an exception has occurred. The simplest form of this reporting is to print information to standard error indicating that an exception has occurred, and possibly provide some guidance on how to correct the issue.

More sophisticated systems report issues through logging and APM tools like Retrace. APM tools simplify the process by centralizing the reporting of issues and monitoring as well as quickly identifying ways to improve performance and fix hidden exceptions.

Retrace is starting to support Ruby applications to ensure no errors slip through the cracks as deployments get pushed into production.

How to handle an exception

Ruby’s exception handling mechanism is simple: it places the keyword “rescue” after any code that would probably throw an exception. Ruby does require some form of “begin” to appear before the rescue. The general syntax for the rescue statement is as follows:

begin
    #... process, may raise an exception
rescue =>
    #... error handler
else
    #... executes when no error
ensure
    #... always executed
end

The code between “begin” and “rescue” is where a probable exception might occur. If an exception occurs, the rescue block will execute. You should try to be specific about what exception you’re rescuing because it’s considered a bad practice to capture all exceptions.

Be specific about what you rescue

You should specify what your rescue statement can handle. If your rescue block can handle multiple erroneous conditions, use the most general class name possible. In some cases, this is StandardError, but often it’s a subtree of the class hierarchy under StandardError.

A bare rescue will capture StandardError and all of its subtypes—that is, it’ll catch any class raised that extends StandardError. This is problematic. You should rescue only those exceptions you can actually do something about. Other exceptions should be allowed to flow past your rescue statement.

If you’re using an APM tool like Retrace, it will allow you to ignore certain exceptions that you can’t fix and are just creating unwanted noise.

Multiple rescues

In cases where multiple rescues are possible and the rescue operation is different for each, you can specify multiple rescue blocks. An example might be something like this:

3.0.0 :001 > values = []
3.0.0 :002 > begin
3.0.0 :003?>     File.readlines('input.txt').each { |line| values <> Float(line) }
3.0.0 :004?> rescue Errno::ENOENT
3.0.0 :005?>     p 'file not found'
3.0.0 :006?> rescue ArgumentError
3.0.0 :007?>     p 'file contains unparsable numbers'
3.0.0 :008?> else
2.5.3 :009?>     print values
3.0.0 :010?> end
[3.0, 4.5, 9.9, 10.0] => nil

In this example, two possible issues may occur. First, the file might not be found. Second, an ArgumentError might occur if the content of input.txt can’t be parsed to a floating-point number. In each case, the rescue operation is different.

Assigning the error to a variable

As mentioned before, each rescued exception can be assigned to a variable. This allows you to inspect the error that occurred. In the following example, all StandardErrors are captured by the rescue, and the exception message is printed:

3.0.0 :013 > begin
3.0.0 :014?>     IO.readlines('input.txt').each { |line| values << Float(line) } 3.0.0 :015?> rescue => error
3.0.0 :016?>     p error.message
3.0.0 :017?> end
"invalid value for Float(): "fooie\n""

Don’t rescue all exceptions

You can force Ruby to capture all possible exceptions (except fatal exceptions, which are not rescuable) by specifying the class name “exception” in the rescue. However, you never want to do this. Exceptions outside of the StandardError hierarchy are used in the general function of the Ruby environment. By catching them, you can break your program in weird and unexpected ways. Consider the following example:

3.0.0 :001 > points_scored = 100.0
3.0.0 :002 > points_possible = nil
3.0.0 :003 > begin
3.0.0 :004?>     grade = points_scored / points_possible
3.0.0 :005?> rescue TypeError
3.0.0 :006?>     p "The instructor did not provide a value for points possible"
3.0.0 :007?>     grade = 0.0
3.0.0 :008?> else
3.0.0 :009?>     p "Your grade is #{grade}%"
3.0.0 :010?> ensure
3.0.0 :011 >     p "Grade Report Complete"
3.0.0 :012?> end
"The instructor did not provide a value for points possible"
"Grade Report Complete"
=> 0.0

Statement rescue

The syntax of a statement rescue is as follows:

rescue ...error handler...

This can be useful for dealing with simple issues in which a potential exception may occur. For example:

3.0.0 :001 > points_scored = 100.0
3.0.0 :002 > points_possible = nil
3.0.0 :003 > grade = points_scored / points_possible rescue 0.0
=> 0.0

In this case, it’s possible for the math on line 3 to fail. By using nil here, we cause a TypeError. The rescue block will catch all StandardError exceptions and set the grade to zero. This can be a handy shortcut for dealing with these scenarios. You can even place an entire block of code in the rescue here if there are multiple steps to the correction.

3.0.0 :001 > score = 80.0
3.0.0 :002 > possible_score = nil
3.0.0 :003 > grade = score / possible_score rescue begin
3.0.0 :004?>     print 'math error'
3.0.0 :005?>     0.0
3.0.0 :006?> end
math error => 0.0
3.0.0 :007 > grade
=> 0.0

Rescuing loops

The “rescue” keyword can be applied to loops as well. After all, loops are just statements in Ruby. The syntax for rescue on the various loops looks like this:

while  do
    #... loop body
end rescue ...error handler...

begin
    #... loop body
end while  rescue ...error handler...

until  do
    #... loop body
end rescue ...error handler...

for  in expression do
    #... loop body
end rescue ...error handler...

There are some things to consider when using a rescue on a loop. Specifically, the rescue is executed after the loop terminates.

For example:

3.0.0 :001 > scores = [80.0, 85.0, 90.0, 95.0, 100.0]
3.0.0 :002 > possibles = [100.0, 100.0, 100.0, nil, 100.0]
3.0.0 :003 > grades = []
3.0.0 :004 > for idx in 0..(scores.length-1)
3.0.0 :005?>     grades[idx] = scores[idx] / possibles[idx]
3.0.0 :006?> end rescue grades[idx] = 0.0
3.0.0 :007 > grades
=> [0.8, 0.85, 0.9, 0.0]

Of course, this causes a problem. The last score/possibles pair wasn’t evaluated, which isn’t an ideal solution. Ruby provides a way to retry the block between “begin” and “retry” that can fix this problem.

Using retry

In the following example, we’ll build out a full rescue block and then use that rescue block to correct the error condition. Then we will use “retry” to re-execute starting from the begin block. This will give us an answer for each score.

3.0.0 :001 > scores = [80.0, 85.0, 90.0, 95.0, 100.0]
3.0.0 :002 > possibles = [100.0, 100.0, 100.0, nil, 100.0]
3.0.0 :008 > for idx in 0..(scores.length-1)
3.0.0 :009?>     begin
3.0.0 :010?>         grades[idx] = scores[idx] / possibles[idx]
3.0.0 :011?>     rescue TypeError
3.0.0 :012?>         possibles[idx] = 100.0
3.0.0 :013?>         retry
3.0.0 :014?>     end
3.0.0 :015?> end
=> 0..4
3.0.0 :016 > grades
=> [0.8, 0.85, 0.9, 0.95, 1.0]

Using next

Although next isn’t actually part of the rescue mechanism, we can make the previous example less presumptive. A TypeError is raised when no “possibles” value exists in the previous example. We’re setting a value in possibles and retrying the math. This is fine if we understand that the correct value of the possibles is 100.0 for any given evaluation. If that’s not appropriate, we can use a sentinel value to indicate that a computation error occurred and use “next” to cause the loop to proceed to the next evaluation.

3.0.0 :001 > scores = [80.0,85.0,90.0,95.0,100.0]
3.0.0 :002 > possibles = [80.0,110.0,200.0,nil,100.0]
3.0.0 :003 > grades=[]
3.0.0 :004 > for idx in 0..(scores.length-1)
3.0.0 :005?>     begin
3.0.0 :006?>         grades[idx] = scores[idx] / possibles[idx]
3.0.0 :007?>     rescue TypeError
3.0.0 :008?>         grades[idx] = 'Computation Error'
3.0.0 :009?>         next
3.0.0 :010?>     end
3.0.0 :011?> end
3.0.0 :012 > grades
=> [1.0, 0.7727272727272727, 0.45, "Computation Error", 1.0]

Rescue each

You may be wondering if you can use “rescue” with an “each” iterator. The answer is yes. The syntax is as follows:

.each {} rescue ...error handler...

For example:

3.0.0 :001 > values = [1,2,3,0]
3.0.0 :002 > results = []
3.0.0 :003 > values.each { |value| results <<; value / value } rescue results <;< 'undefined' 2.5.3 :004 > results
=> [1, 1, 1, "undefined"]

For a deeper understanding on how to handle exceptions in Ruby refer to the official Ruby Exception Handling documentation.

Conclusion

The rescue block in Ruby is very powerful. It’s vastly easier to use than error codes. Rescue lets you create more robust solutions by providing a simple way to deal with common errors that might occur in your program. At a minimum, you can provide a graceful shutdown and reporting of problems in your code. If you’re looking for something more robust, check out Retrace for Ruby.

]]>
What Is Infrastructure as Code? How It Works, Best Practices, Tutorials https://stackify.com/what-is-infrastructure-as-code-how-it-works-best-practices-tutorials/ Mon, 18 Sep 2023 13:51:57 +0000 https://stackify.com/?p=26337 In the past, managing IT infrastructure was a hard job. System administrators had to manually manage and configure all of the hardware and software that was needed for the applications to run.

However, in recent years, things have changed dramatically. Trends like cloud computing revolutionized—and improved—the way organizations design, develop, and maintain their IT infrastructure.

One of the critical components of this trend is called “infrastructure as code,” and it’s what we’re going to talk about today.

Defining Infrastructure as Code

Let’s start by defining infrastructure as code, or IaC. You’ll learn what this means and what problem it solves.

Wikipedia defines IaC as follows:

 Infrastructure as code is the process of managing and provisioning computer data centers through machine-readable definition files, rather than physical hardware configuration or interactive configuration tools.

As far as definitions go, this one isn’t bad, but it’s somewhat wordy. Let’s try and rewrite a simpler version:

Infrastructure as code (IaC) means to manage your IT infrastructure using configuration files.

The next question then becomes “Why would you want to do that?”

What Problem Does IaC Solve?

With the “what” out of the way, let’s turn our focus to the “why” of infrastructure as code. Why is it needed? What problem does it solve?

Historically, managing IT infrastructure was a manual process. People would physically put servers in place and configure them

The Pain of Managing IT Infrastructure

Historically, managing IT infrastructure was a manual process. People would physically put servers in place and configure them. Only after the machines were configured to the correct setting required by the OS and applications would those people deploy the application. Unsurprisingly, this manual process would often result in several problems.

The first big problem is cost. You’d have to hire many professionals to perform the necessary tasks at each step of the process, from network engineers to hardware maintenance technicians. All of those people need to be paid, obviously, but they also need to be managed. That leads to more management overhead and adds more complexity to communication inside the organization. The result? Dollars go away. And we didn’t even mention building and maintaining your own data centers, which would increase the costs by orders of magnitude.

The next big problems are scalability and availability. But in the end, it all comes down to speed. Since manual configuration is so slow, applications would often struggle with spikes in access, while the system administrators would be desperately trying to set up servers to manage the load. This necessarily impacts availability. If the organization didn’t have backup servers or even data centers, then the application could be unavailable for long periods.

Last but not least on our list of problems comes inconsistency. If you have several people manually deploying configurations, discrepancies aren’t going to be unavoidable.

cloud computing

Cloud Computing: A Cure?

Cloud computing came to relieve some of the pains you’ve just read about. It frees you from having to build and maintain your data centers and the high cost associated with it.

Cloud computing is far from being a panacea, though. While it allows you to set up your infrastructure needs quickly—thus solving severe problems such as high availability and scalability—it does nothing to solve the inconsistency issues. When you have more than one person performing the configurations, you’re bound to get discrepancies.

Infrastructure as Code: The Missing Piece of the Puzzle

Let’s review the IaC definition we’ve presented some sections ago:

 Infrastructure as code (IaC) means to manage your IT infrastructure using configuration files.

The key takeaway from the definition is this: Before IaC, IT personnel would have to manually change configurations to manage their infrastructure. Maybe they would use throwaway scripts to automate some tasks, but that was the extent of it. With IaC, your infrastructure’s configuration takes the form of a code file. Since it’s just text, it’s easy for you to edit, copy, and distribute it. You can—and should—put it under source control, like any other source code file.

Infrastructure as Code Benefits

You’ve just read about the problems caused by a manual approach to infrastructure management. We’ve told you how cloud computing is a solution to some of those problems, but not all. Then, we wrapped up by arguing that IaC is the final piece of the puzzle.

Now we’re going to dive into some of the benefits your organization will reap by adopting an IaC solution.

The first significant benefit IaC provides is speed. Infrastructure as code enables you to quickly set up your complete infrastructure by running a script

Speed

The first significant benefit IaC provides is speed. Infrastructure as code enables you to quickly set up your complete infrastructure by running a script. You can do that for every environment, from development to production, passing through staging, QA, and more. IaC can make the entire software development lifecycle more efficient.

Consistency

Manual processes result in mistakes, period. Humans are fallible. Our memories fault us. Communication is hard, and we are in general pretty bad at it. As you’ve read, manual infrastructure management will result in discrepancies, no matter how hard you try. IaC solves that problem by having the config files themselves be the single source of truth. That way, you guarantee the same configurations will be deployed over and over, without discrepancies.

Accountability

This one is quick and easy. Since you can version IaC configuration files like any source code file, you have full traceability of the changes each configuration suffered. No more guessing games about who did what and when.

More Efficiency During the Whole Software Development Cycle

By employing infrastructure as code, you can deploy your infrastructure architectures in many stages. That makes the whole software development lif cycle more efficient, raising the team’s productivity to new levels.

You could have programmers using IaC to create and launch sandbox environments, allowing them to develop in isolation safely. The same would be true for QA professionals, who can have perfect copies of the production environments in which to run their tests. Finally, when it’s deployment time, you can push both infrastructure and code to production in one step.

lower infrastructure management costs

Lower Cost

One of the main benefits of IaC is, without a doubt, lowering the costs of infrastructure management. By employing cloud computing along with IaC, you dramatically reduce your costs. That’s because you won’t have to spend money on hardware, hire people to operate it, and build or rent physical space to store it. But IaC also lowers your costs in another, subtler way, and that is what we call “opportunity cost.”

You see, every time you have smart, high-paid professionals performing tasks that you could automate, you’re wasting money. All of their focus should be on tasks that bring more value to the organization. And that’s where automation strategies—infrastructure as code among them—come in handy. By employing them, you free engineers from performing manual, slow, error-prone tasks so they can focus on what matters the most.

How Does IaC Work?

IaC tools can vary as far as the specifics of how they work, but we can generally divide them into two main types: the ones that follow the imperative approach, and the ones who follow the declarative approach. If you think the categories above have something to do with programming language paradigms, then you’re spot on!

The imperative approach “gives orders.” It defines a sequence of commands or instructions so the infrastructure can reach the final result.

A declarative approach, on the other hand, “declares” the desired outcome. Instead of explicitly outlining the sequence of steps the infrastructure needs to reach the final result, the declarative approach shows what the final result looks like.

Common IaC Tools

  1. Terraform: Terraform stands out as an open-source Infrastructure as Code (IaC) tool, empowering users to articulate infrastructure configurations through a declarative syntax. What sets it apart is its remarkable versatility, as it seamlessly extends its support to various cloud providers and on-premises environments.
  2. AWS CloudFormation: AWS CloudFormation offers a powerful means to express and provision your AWS infrastructure in code form. Leveraging JSON or YAML templates, it elegantly outlines resources and their interdependencies, simplifying the management of your AWS resources.
  3. Ansible: Ansible emerges as a versatile open-source automation tool that finds utility in the realm of Infrastructure as Code (IaC). It distinguishes itself with its use of straightforward and human-readable YAML scripts to streamline the automation of configuration, deployment, and orchestration tasks across a diverse spectrum of systems and cloud platforms.
  4. Azure Resource Manager (ARM) Templates: Microsoft Azure’s Infrastructure as Code (IaC) solution, Azure Resource Manager (ARM), relies on JSON files encapsulating the definitions of Azure resources and their interdependencies. This approach facilitates the seamless provisioning of infrastructure on the Azure cloud platform while preserving clarity and manageability.
  5. Netreo: Netreo emerges as an all-encompassing Infrastructure as a Code (IaC) platform meticulously crafted to automate and oversee IT infrastructure. Its extensive repertoire encompasses an array of capabilities such as network monitoring, configuration management, and automation, rendering it an indispensable asset for those deeply engaged in the IaC landscape.

In this diverse landscape of IaC tools, organizations are bestowed with the freedom to select the one that most harmoniously aligns with their distinctive prerequisites and operational methodologies.

Learn Some Best Practices

Now we present a short list of best practices you can use the make the most out of your IaC strategy.

  • Make code your single source of truth. You should explicitly code all the infrastructure specifications in configuration files. Your configuration files should be the single source of truth for all your infrastructure management concerns.
  • Version control all of your configuration files. This probably should go without saying, but put all of your config files under source control.
  • Use little documentation (or none at all) for your infrastructure specifications. This point is the logical consequence of the first one. Since your config files should be your single source of truth, there should be no need for more documentation. External documentation can easily get out of sync with the real configurations, but that won’t happen with the config files.
  • Test and Monitor Your Configurations. IaC is code, and like all code, it can be tested. So test it you should! By employing testing and monitoring tools for IaC, you can check for errors and inconsistencies in your servers before you deploy them to production.

Resources At Your Disposal

What follows is a list of useful resources to help you with your IaC learning:

Try Stackify’s free code profiler, Prefix, to write better code on your workstation. Prefix works with .NET, Java, PHP, Node.js, Ruby, and Python.

Infrastructure as Code Saves You Time and Money

Infrastructure as code is a crucial part of the DevOps movement. If you think of cloud computing as the first step to solving many of the problems caused by manual IT management, then it’s fair to say the IaC is the next logical step. It takes cloud computing to its fullest potential, and it frees developers and other professionals from performing manual, error-prone tasks. Plus, it lowers costs and improves efficiency at all stages of the software development lifecycle.

Besides IaC, it also helps to have a tool like Retrace. Retrace is a code-level APM solution that can manage and monitor your app’s performance throughout the entire development lifecycle. Plus, it offers many other features, such as error tracking, log management, and application metrics. Start your trial today.

]]>
What are Microservices? Code Examples, Best Practices, Tutorials and More https://stackify.com/what-are-microservices/ Fri, 15 Sep 2023 09:11:40 +0000 https://stackify.com/?p=11884 Microservices are increasingly used in the development world as developers work to create larger, more complex applications that are better developed and managed as a combination of smaller services that work cohesively together for more extensive, application-wide functionality.

Tools such as Service Fabric are rising to meet the need to think about and build apps using a piece-by-piece methodology that is, frankly, less mind-boggling than considering the whole of the application at once.

Today, we’ll take a look at microservices, the benefits of using this capability, and a few code examples.

What are Microservices?

Microservices are an architectural style that develops a single application as a set of small services. Each service runs in its own process. The services communicate with clients, and often each other, using lightweight protocols, often over messaging or HTTP.

Microservices can be thought of as a form of service-oriented architecture (one of the most critical skills for Java developers) wherein applications are built as a collection of different smaller services rather than one whole app.

Instead of a monolithic app, you have several independent applications that can run on their own. You can create them using different programming languages and even different platforms. You can structure big and complicated applications with simpler and independent programs that execute by themselves. These smaller programs are grouped to deliver all the functionalities of the big, monolithic app.

Microservices captures your business scenario, answering the question, “What problem are you trying to solve?”

Instead of large teams working on large, monolithic projects, smaller, more agile teams develop the services using the tools and frameworks they are most comfortable with. Each of the involved programs is independently versioned, executed, and scaled. These microservices can interact with other microservices and can have unique URLs or names while being always available and consistent even when failures are experienced.

What are the Benefits of Microservices?

There are many benefits to using microservices. Some of them are related to how they allow your developers to write code. Other influence your architecture.

Microservices are small applications that your development teams create independently. Since they communicate via messaging if at all, they’re not dependent on the same coding language. Developers can use the programming language that they’re most familiar with. This helps them come work faster, with lower costs and fewer bugs

Since your teams are working on smaller applications and more focused problem domains, their projects tend to be more agile, too. They can iterate faster, address new features on a shorter schedule, and turn around bug fixes almost immediately. They often find more opportunities to reuse code, also.

Microservices improve your architecture’s scalability, too.

With monolithic systems, you usually end up “throwing more hardware” at the problem or purchasing expense and difficult-to-maintain enterprise software. With microservices, you can scale horizontally with standard solutions like load balancers and messaging.

Also, as more and more enterprises embrace the cloud, you’re probably looking that way, too. Microservices are a great way to get there.

Cloud platforms lend themselves to newer technologies like containerization. Microservices lend themselves to containerization too, since they already are small applications with a limited set of dependencies. This means you can scale your services horizontally with technologies like Docker and Kubernetes without writing any customized code.

Examples of Microservices Frameworks for Java

There are several microservices frameworks that you can use for developing for Java. Some of these are:

  • Spring Boot. This is probably the best Java microservices framework that works on top of languages for Inversion of Control, Aspect-Oriented Programming, and others.
  • Jersey. This open-source framework supports JAX-RS APIs in Java and is very easy to use.
  • Swagger. Helps you document API as well as gives you a development portal, which allows users to test your APIs.
  • Quarkus. This is a lightweight Java framework optimized for GraalVM and HotSpot, and it’s tightly integrated with Kubernetes.
  • Micronaut. It’s based on the Netty framework, which makes it well-suited for microservices that need to handle a lot of traffic.
  • Helidon. A microservices framework developed by Oracle. It is based on the MicroProfile specification, making it interoperable with other MicroProfile-based frameworks.
  • AxonIQ. A microservices framework designed for event-driven architectures. It provides a comprehensive toolkit for building event-driven microservices, including a message bus, event sourcing, and CQRS.

Others that you can consider include: Dropwizard, Ninja Web Framework, Play Framework, RestExpress, Restlet, Restx, and Spark Framework.

How to Create Using Dropwizard

DropWizard pulls together mature and stable Java libraries in lightweight packages that you can use for your applications. It uses Jetty for HTTP, Jersey for REST, and Jackson for JSON, along with Metrics, Guava, Logback, Hibernate Validator, Apache HttpClient, Liquibase, Mustache, Joda Time, and Freemarker.

You can setup a Dropwizard application using Maven. How?

In your POM, add in a dropwizard.version property using the latest version of DropWizard.

<properties>

<dropwizard.version>LATEST VERSION</dropwizard.version>

</properties>

Then list the dropwizard-core library:

<dependencies>

<dependency>

<groupId>io.dropwizard</groupId>

<artifactId>dropwizard-core</artifactId>

<version>${version}</version>

</dependency>

</dependencies>

This will set up a Maven project for you. From here, you can create a configuration class, an application class, a representation class, a resource class, or a health check, and you can also build Fat JARS, then run your application.

Check out the Dropwizard documentation at this link. The Github library is here.

Sample code:

package com.example.helloworld;

import com.yammer.dropwizard.config.Configuration;

import com.fasterxml.jackson.annotation.JsonProperty;

import org.hibernate.validator.constraints.NotEmpty;

public class HelloWorldConfiguration extends Configuration {

@NotEmpty

@JsonProperty

private String template;

@NotEmpty

@JsonProperty

private String defaultName = "Stranger";

public String getTemplate() {

return template;

}

public String getDefaultName() {

return defaultName;

}

}

Microservices with Spring Boot

Spring Boot gives you Java application to use with your own apps via an embedded server. It uses Tomcat, so you do not have to use Java EE containers. A sample Spring Boot tutorial is at this link.

You can find all Spring Boot projects here, and you will realize that Spring Boot has all the infrastructures that your applications need.

It doesn’t matter if you are writing apps for security, configuration, or big data; there is a Spring Boot project for it.

Spring Boot projects include:

  • IO Platform: Enterprise-grade distribution for versioned applications.
  • Framework: For transaction management, dependency injection, data access, messaging, and web apps.
  • Cloud: For distributed systems and used for building or deploying your microservices.
  • Data: For microservices that are related to data access, be it map-reduce, relational, or non-relational.
  • Batch: For high levels of batch operations.
  • Security: For authorization and authentication support.
  • REST Docs: For documenting RESTful services.
  • Social: For connecting to social media APIs.
  • Mobile: For mobile Web apps.

Sample code:

import org.springframework.boot.*;

import org.springframework.boot.autoconfigure.*;

import org.springframework.stereotype.*;

import org.springframework.web.bind.annotation.*;

@RestController

@EnableAutoConfiguration

public class Example {

@RequestMapping("/")

String home() {

return "Hello World!";

}

public static void main(String[] args) throws Exception {

SpringApplication.run(Example.class, args);

}

}

Jersey

Jersey RESTful framework is open source, and it is based on JAX-RS specification. Jersey’s applications can extend existing JAX-RS implementations and add features and utilities that would make RESTful services simpler, as well as making client development easier.

The best thing about Jersey is its exceptional documentation. It’s filled with excellent examples. Jersey is also fast and has extremely easy routing.

The documentation on how to get started with Jersey is at this link, while more documentation can be found here.

A sample code that you can try:

package org.glassfish.jersey.examples.helloworld;

 

import javax.ws.rs.GET;

import javax.ws.rs.Path;

import javax.ws.rs.Produces;

 

@Path("helloworld")

public class HelloWorldResource {

public static final String CLICHED_MESSAGE = "Hello World!";

 

@GET

@Produces("text/plain")

public String getHello() {

return CLICHED_MESSAGE;

}

}

Jersey is very easy to use with other libraries, such as Netty or Grizzly, and it supports asynchronous connections. It does not need servlet containers. It does, however, have an unpolished dependency injection implementation.

Play Framework

Play Framework gives you an easier way to build, create, and deploy Web applications using Scala and Java. This framework is ideal for RESTful application that requires you to handle remote calls in parallel. It is also very modular and supports async. Play Framework also has one of the biggest communities out of all microservices frameworks.

Sample code you can try:

package controllers;

import play.mvc.*; 

public class Application extends Controller { 
public static void index() {
render();
} 

public static void sayHello(String myName) {
render(myName);
}

}

Restlet

Restlet helps developers create fast and scalable Web APIs that adhere to the RESTful architecture pattern. The framework has good routing and filtering. It’s available for Java SE/EE, OSGi, Google’s AppEngine (which is part of Google Compute), Android, and many other Java platforms. It’s a self-sufficient framework that even ships with its own webserver.

Restlet comes with a steep learning curve that is made worse by a closed community, but you can probably get help from people at StackOverflow.

Sample code:

package firstSteps;

import org.restlet.resource.Get;

import org.restlet.resource.ServerResource;

/**

* Resource which has only one representation.

*/

public class HelloWorldResource extends ServerResource {

@Get

public String represent() {

return "hello, world";

}

}

Best Practices for Microservices

You should be able to tell by now that making the shift to microservices creates a lot of benefits for development, operations, and the business. They create opportunities for increased scalability, greater reliability, and cost savings. But, there’s no such thing as a free lunch. Microservices come with pitfalls of their own.

Here are some best practices that will help your migration.

Each of your microservices should use their own data store. You want the development (and dev-ops) team to choose the database for each of their service. They should have an opportunity to choose the data store that best suits their project. At the same time, if teams share a database, it’s too easy for them to share a schema, creating a monolithic service under a different name.

Deploying microservices in containers isn’t just a good idea. It’s a best practice, too. I’ve mentioned several times that microservice teams should choose their own tools. How do operations and dev-ops manage the chaos this creates? By using containers, so you can deploy and orchestrate your system with a single set of tools.

There’s a reason why RESTful services and microservices are often associated with each other. It’s because the best microservices architectures treat their services as stateless. REST’s state transfer that pushes state down to the clients means that you can treat your servers as stateless, and run your code as interchangeable parts of a whole. You only need to worry about making sure that there are enough services available to handle the load. And, if one fails, another can pick up the slack.

Additional Resources and Tutorials on Microservices

For further reading and information on microservices, including some helpful tutorials, visit the following resources:

In this article, we’ve discussed what microservices are, and how they can help you improve your enterprise architecture. After defining what these services are, we covered their major benefits. Then we looked at some of the most popular microservice APIs for Java. Then, we wrapped up with a look at microservices best practices and a list of resources here on Stackify’s website.

Microservices are a great addition to your enterprise. But, it helps to have a tool like Retrace to help you monitor them.

Retrace is a code-level APM solution that can manage and monitor your app’s performance throughout the entire development lifecycle. Plus, it offers many other features, such as error tracking, log management, and application metrics.

Start your trial today.

Try Stackify’s free code profiler, Prefix, to write better code on your workstation. Prefix works with .NET, Java, PHP, Node.js, Ruby, and Python.

]]>
Install Ruby on Your Mac: Everything You Need to Get Going https://stackify.com/install-ruby-on-your-mac-everything-you-need-to-get-going/ Thu, 07 Sep 2023 10:08:47 +0000 https://stackify.com/?p=25058 In this post, we’re going to show you how to install Ruby on your Mac. Along the way, we’ll learn about the steps involved and various bits of knowledge required to get up and going. So if you’re totally new, don’t worry! I’ll list each step and follow it with an “extra credit” section where I’ll explain that step in depth. If you’ve done this sort of thing before and just need some directions, I’ve included a TLDR section showing what commands to run.

Before We Start…What is Ruby?

Ruby is an open-source programming language with a strong developer focus. Created in 1996 by Yukihiro Matsumoto, Ruby became really popular in the late 2000s with the introduction of the Ruby on Rails web framework. While Ruby is used quite frequently for web development, it’s also popular as a scripting language.

Ruby is known for being easy to learn and fun to use. So let’s find out how easy it is to get up and running!

What We’re Going to Do

  1. Open up the terminal
  2. Install a package manager
  3. Use the package manager to install Ruby
  4. Update our PATH
  5. Write and run our first Ruby program

What You’ll Need

  • An internet connection
  • Administrator privileges (you should have this if you’re working on a personal device)
  • 15 minutes (or just a few if you only need the commands)

TLDR—Run These Commands From the Terminal

/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"
brew install ruby
echo 'export PATH="/usr/local/opt/ruby/bin:$PATH"' >> ~/.bash_profile
source ~/.bash_profile

Step 1: Open up the Terminal

The terminal application on macOS is an operating system command line interface (CLI) that comes installed on new Macs. You can quickly open the terminal by doing the following:

  • Type ⌘+space bar. This brings up the macOS spotlight search, a search utility for opening apps on your Mac.
  • Type terminal into the spotlight search.
  • Press Enter.

Extra Credit for Step 1

When you open a terminal (assuming zero configuration), you start at your home directory. Did you know that a version of Ruby comes installed on your Mac by default?

We can see that by typing some commands into our terminal. The which command allows us to see where on the computer an executable file lives.

which ruby

We passed Ruby as an argument, so the command is finding the Ruby executable location. If Ruby isn’t installed or available to us, the which command will let us know it couldn’t find Ruby.

Now let’s see which version of Ruby we have installed by typing in the following command:

ruby -v

Here, we’re invoking the Ruby CLI and passing the option -v to it. The -v option tells the Ruby CLI to return the version of the Ruby installation to us.

For Mac M1, it returns the following:

ruby 2.6.10p210 (2022-04-12 revision 67958) [universal.arm64e-darwin22]

That means M1 Macs come with Ruby version 2.6 installed.

If you don’t need the latest and greatest Ruby version, you could stop here. But as good software engineers and system administrators, we like to stay on top of things and install the updated versions when we can. Let’s do that by installing a package manager.

Step 2: Install a Package Manager

Hold on! What’s a package manager? A package manager is an application whose job is to manage software on your computer. In this case, managing means installing, updating, and removing software as needed. Package managers will install software in a consistent manner and keep your computer tidy.

As it turns out, macOS has an awesome package manager called Homebrew. Ironically, Homebrew is written in Ruby! Let’s get that installed.

The Homebrew homepage has the install information. We’re going to follow that by running this command in our terminal that we opened in step 1:

/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

This command is going to install Homebrew for us. The cool thing about the Homebrew install script is that it will tell you what it’s going to do and prompt you for a yes or no before proceeding. The install script is very informative. One of the important things it points out for us will be that the install script is going to create some subdirectories in the /bin/ directory. More on that later.

Extra Credit for Step 2

Whoa! What’s that install command doing anyway? I’m a big proponent of understanding commands that you paste into your terminal before you run them. The terminal is a really cool and powerful program, but we can harm our machine if we paste someone’s malicious code in there, so it’s important to understand what we’re doing.

I look at this command and see a few notable things:

  • /bin/bash -c
  • curl -fsSL
  • curl is getting content from this address: https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh
  • The output of the curl command is interpolated for the Ruby command

Let’s Explore What Each of These Mean

The /bin/bash portion of the command is giving our terminal a specific location to an executable using the bash command. If you recall from our earlier step, when we used which ruby, we found that the Ruby command was coming from the location /usr/bin/ruby in our bin directory. On Unix-like operating systems such as macOS, /usr/bin/ is where the operating system installs distribution executable files. Distribution executable files are executable files that come with and are managed by your operating system.

I also notice that the Ruby command is getting called with the -c flag. If we type man ruby into our terminal, we can explore the documentation and find out what the -c flag does.

If we scroll down the man page to get to the -c flag, we’ll see that it says, “

Causes Ruby to check the syntax of the script and exit

                    without executing. If there are no syntax errors, Ruby

                    will print “Syntax OK” to the standard output.

” To get out of the man page, just hit q.

As the documentation suggests, the above command simply checks the syntax of the Ruby script and prints a standard output “Syntax Ok” if the syntax is correct.

The curl command

Alright. Now let’s look at the curl command. The curl command is actually cURL, which stands for “client URL.” The Homebrew install script uses curl to fetch data from GitHub.  The command is also using several flags. Again, we can use the man command and pass curl to it…which, while being slightly funny, is also super useful and can help us find out what these flags are doing. So here’s the condensed version of what we need to find in man curl.

  • -f means fail silently on server errors. This is to prevent seeing a text representation of an HTML server error document
  • -s means use silent mode. Silent mode doesn’t show the progress meter or error messages.
  • -S means to show an error message if curl fails. It’s used to modify the -s option to still be silent unless the curl command fails.
  • -L is the location flag. This is a convenience flag to handle redirect HTTP response codes. If the document has moved and there’s a response indicating its new location, curl will go and try to fetch it at that location.

Cool. That was pretty straightforward. We’re fetching data with some flags that modify the way curl outputs status messages.

Fetching raw content from GitHub

If you actually paste the URL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh into your browser, you’ll see that it brings up a Ruby script file. This is GitHub’s site that hosts raw files that are stored in a GitHub repository. It’s useful for fetching just the content of a script.

Interpolation, a fancy word for fancy folks

Oxford defines interpolation as “the insertion of something of a different nature into something else.” In our case, we’re doing string interpolation in Bash. We’re taking the output of one command and treating it like string input. In Bash, the best way to do string interpolation is to call a command from within a set of parenthesis preceded by a dollar sign. So since we’re wrapping the curl command in the parenthesis, like this…

$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)

…we’re treating the output like a string to the Ruby command.

Putting it all together

Ironically, we’re using Ruby to install the package manager, which we’ll use to install a newer version of Ruby!

  1. We’re calling the Ruby command and telling it to execute the content we’re passing to it instead of looking for a file.
  2. We’re pulling a raw Ruby script from https://raw.githubusercontent.com/Homebrew/install/master/install. And we’re doing it without any extra output from curl by passing those command line options. This is smart because the Ruby command wouldn’t know how to interpret any output from curl.
  3. We’re interpolating that script as input to the Ruby command!

Wow. There’s a lot to understand, even about relatively small commands! What I hope you take away from this section is that taking the time to understand some of the extra stuff is important and that the man command is your friend.

Now that we understand this step better, let’s actually install the latest version of Ruby.

Step 3: Use the Package Manager to Install Ruby

Alright, so now that Homebrew is installed, we can use it to install a newer version of Ruby. The command is pretty straightforward:

brew install ruby

With this, Homebrew will go out and fetch not only Ruby but also any dependencies Ruby needs to run. On my machine, for example, Homebrew installed LibYAML prior to installing Ruby.

We’re almost ready to write our first Ruby program!

Extra Credit for Step 3

You’ll notice right now that if you run the ruby -v command again, it’s the same version of Ruby that we saw in step 1. What gives?

Homebrew was nice enough to tell us what happened. Here is a snippet of the output from the brew install ruby command:

ruby is keg-only, which means it was not symlinked into /opt/homebrew, because macOS already provides this software and installing another version in parallel can cause all kinds of trouble.

If you need to have Ruby first in your PATH run:

echo 'export PATH="/opt/homebrew/opt/ruby/bin:$PATH"' >> ~/.zshrc
A brief look at how Homebrew installs programs

Remember earlier when I mentioned that package managers like Homebrew keep our machine tidy by installing things in a consistent manner? This output relates to that bit of information. When Homebrew installs a package, it will actually install it in a directory that Homebrew owns.

We mentioned that /usr/bin is for the distribution of executable files. There’s another directory, /usr/local/bin, that was created by Homebrew in step 2. Homebrew actually makes a directory named “Cellar” inside this directory. Homebrew will install packages into the Cellar and then make symlinks from those packages into /usr/local/bin that are available to us. A symlink, or symbolic link, is a special type of file that acts as a redirect to where the actual file lives. This allows Homebrew to be selective about what executables it makes available.

What does that mean for us?

It means that the newer version of Ruby is installed, but Homebrew isn’t going to put it on the PATH for us. It’s not going to do this because of the existing version of Ruby living in /usr/bin. It tells us how to fix this situation by modifying our PATH.

I’ve mentioned the PATH a lot, and we’re going to talk about it next!

Step 4: Update our PATH

The simplest way to do this is to follow the instructions Homebrew gives us. Run this command:

echo 'export PATH="/opt/homebrew/opt/ruby/bin:$PATH"' >> ~/.zshrc

This will update our Bash profile but not our current environment.

You could open a new terminal at this point, but a simpler method to update your environment is to run this command:

source ~/.zshrc

The version of Ruby that is going to take precedence in the terminal is now the version we installed with Homebrew!

Verify that the new version is installed by again checking the version. It should be a more recent version than what was installed on the system by default.

ruby -v

And now you’ll see the newer version of Ruby returned by the above command that you just installed:

ruby 3.2.2 (2023-03-30 revision e51014f9c0) [arm64-darwin22]

Extra Credit for Step 4

There are some more interesting tidbits to unpack here.

  • PATH
  • echo and >>
  • ~/.zshrc
  • source
The PATH variable

PATH is an environment variable. An environment variable is a piece of data that is available for both us and other subprocesses to use every time we open a shell prompt. The PATH contains a list of directories, separated by colons. When you type a command into your shell, it will look for executable files in those directories, in the order they listed.

The PATH variable serves a couple of purposes. One purpose is to provide a single place to refer to and update an executable’s location. Also, the PATH makes our life easier by eliminating the need to refer to executables by their exact location. For example, if we had not followed step 4, we could still access the version of Ruby we installed, but it would be slightly annoying. If we wanted to check our newly installed Ruby version, we would have to refer to the command like this:

/usr/local/opt/ruby/bin/ruby -v

Now imagine typing that in everywhere! It’s not great, and it could also lead to a mess. If you decided to move that executable to another location, you’d have to type in that new location to reference the command. This would be a nightmare if scripts were using the absolute location. They would all break.

You can update your PATH by appending or prepending a directory to it. That’s what this section of the command is doing. It’s prepending a directory to the existing PATH variable.

export PATH=”/opt/homebrew/opt/ruby/bin:$PATH

Echo and the >> operator

The echo command simply returns whatever we type in the shell back to us. For instance, you can run a command to print “Hello World” in the terminal:

echo "Hello World"
Hello World

The redirect operator used in conjunction with echo is a handy way to modify a file’s contents without opening the file. The >> operator tells the shell to append the output of the previous command to a given file.

This is what we’re doing. We’re appending export PATH=”/usr/local/opt/ruby/bin:$PATH” to the end of our Bash profile.

The ZSHRC file

The ~/.zshrc is a special file that’s sourced when a new shell environment is created. The tilde at the start of that file is a directory alias for your home directory. For our purposes, you can think of this file as a place where you store user preferences when you create a new shell environment. This means that any time you open up the terminal program, anything you place in this file will run first. In this case, the PATH environment variable will be updated to prioritize the directory containing our version of Ruby.

Source

The source command takes a file and updates the current shell’s environment to contain any changes or additions in the sourced file. While our shell would source the Bash profile automatically when a new terminal is created, we can do it manually by running the source command ourselves.

Step 5: Write and Run Our First Ruby Program

We’ve now installed Ruby!  Let’s celebrate by running the ceremonial and obligatory “Hello World” program. We’re going to use Vim, a commonly used editor for Ruby developers. Let’s open a file with Vim.

vim hello_world.rb

Now you have to type the character i to go into “insert” mode. Then go ahead and type the following:

puts "hello world"

Now let’s save and quit. Hit the Escape key, then type :wq and hit Enter.

Celebrate and type

ruby hello_world.rb

And that’s it!

There’s no extra credit here. We’ve already covered quite a bit of content. We set out to install Ruby, and along the way, we learned a little bit about several things:

  • Terminal
  • Package management
  • Shell commands
  • PATH
  • How to exit Vim ?
  • And more!

If you’re planning on using Ruby to write a cool business app, take a look at Retrace. Retrace can do all sorts of things for you, including helping you understand your application’s performance.

Try Stackify’s free code profiler, Prefix, to write better code on your workstation. Prefix works with .NET, Java, PHP, Node.js, Ruby, and Python.

Start Free Trial
]]>
.NET Core vs .NET Framework: How to Pick a .NET Runtime for an Application https://stackify.com/net-core-vs-net-framework/ Wed, 06 Sep 2023 07:00:00 +0000 https://stackify.com/?p=12576 A while back we predicted that .NET Core would be the next big thing, offering developers many options in application development. Indeed, there is huge demand for developers skilled in this technology. But how does it differ from the .NET Framework, and what do you need to know to use them both effectively?

Today, we’ll contrast .NET Core vs. .NET Framework to help you choose which one to use for your next project. In this post, we’ll explain their key differences and how to make the best use of each. Let’s begin with a background on .NET.

Historically, the .NET Framework has only worked on Windows devices. The Xamarin and Mono projects worked to bring .NET to mobile devices, macOS and Linux. Now, .NET Core provides a standard base library that’s usable across Windows, Linux, macOS and mobile devices (via Xamarin).

There are four major components of .NET architecture:

  • Common language specification (CLS) defines how objects are implemented so they work everywhere .NET works. CLS is a subset of Common Type System (CTS) – which sets a common way to describe all types
  • Framework class library (FCL) is a standard library that collects reusable classes, interfaces and value types
  • Common language runtime (CLR) is the virtual machine that runs the framework and manages the execution of .NET programs
  • Visual Studio is used to create standalone applications, interactive websites, web applications and web services

.NET Core vs .NET Framework

Microsoft maintains both runtimes for building applications with .NET while sharing many of the same APIs. This shared API is called the .NET Standard.

.NET Core vs. .NET Framework Shared API

Image via Wikipedia

Developers use the .NET Framework to create Windows desktop and server-based applications. This includes ASP.NET web applications. On the other hand, .NET Core is used to create server applications that run on Windows, Linux and Mac. It does not currently support creating desktop applications with a user interface. Developers can write applications and libraries in VB.NET, C# and F# in both runtimes.

C# is an object-oriented language similar to other C-style languages. The learning curve should not be a problem for developers already working with C and similar languages.

F# is a cross-platform language that also uses object-oriented programming.

Visual Basic is available in .NET Framework with limited .NET Core support with .NET Core 2.0.

When to Use .NET Core

A cross-platform and open-source framework, .NET Core is best when developing applications on any platform. .NET Core is used for cloud applications or refactoring large enterprise applications into microservices.

A cross-platform and open-source framework, .NET Core screenshot

Screenshot via Microsoft.com

You should use .NET Core when:

  • There are cross-platform needs. Use it when the application needs to run across multiple platforms such as Windows, Linux and macOS. Those operating systems are supported as development workstations (and the list of supported operating systems is growing):
    • Visual Studio is compatible on Windows with a new limited version on macOS
    • Visual Studio Code can be used on Windows, Linux and macOS
    • All supported platforms allow the use of the command line
  • Using Microservices. Microservices, a form of service-oriented architecture, are software applications consisting of small, modular business services. Each service can run a unique process, be deployed independently and be created in different programming applications. .NET Core allows a mix of technologies, is lightweight and scalable for each microservice
  • Working with Docker containers. Containers and microservices architecture are often used together. Because it is lightweight and modular, .NET Core works very well with containers. You can deploy cross-platform server apps to Docker containers. .NET Framework works with containers, but the image size is larger
  • You have high-performance and scalable system needs. Microsoft recommends running .NET Core with ASP.NET Core for the best performance and scale. This becomes important when using hundreds of microservices. In such a case, a lower number of servers and virtual machines is best. The efficiency and scalability gained should translate to a better user experience in addition to cost savings
  • You are running multiple .NET versions side-by-side. To install applications with dependencies on different versions of frameworks in .NET, developers need to use .NET Core. Multiple services are executable on the same server with different versions of .NET
  • You want command line interface (CLI) control. Some developers prefer working in lightweight editors and command line control. .NET Core has a CLI for all supported platforms and requires minimal installation on production machines. And, there still is the opportunity to switch to an IDE, such as Visual Studio IDE

When Not to Use .NET Core

.NET Core does not have some of the .NET features nor support for all libraries and extensions. As such, you may encounter a few situations in which .NET Core may not be the best option (though continued development will likely eliminate this drawback). Consider the following scenarios:

  • Windows Forms and WPF applications are not supported – You still have to use Mono to make a .NET desktop application for macOS
  • ASP.NET WebForms don’t exist – Though Microsoft provides strategies for migrating ASP.NET Web Forms apps
  • You need to create a WCF service – .NET Core does not currently support WCF. Instead, you would need to make a REST API with ASP.NET Core MVC
  • Missing 3rd-party library support – .NET Core provides a compatibility shim between .NET Framework and .NET Core. But, you may still have issues with compatibility if the class library uses any .NET Framework APIs that are not supported (though this will help bridge a lot of class libraries to .NET Core)
  • Missing .NET Framework features – Some .NET Framework functionality is still missing in .NET Core. For example, Entity Framework Core is not the exact same as Entity Framework v6
  • You need to access Windows-specific APIs – If your application needs to work with the Windows Registry (WMI or other Windows specific APIs), it won’t work with .NET Core. It is designed to be more sandboxed away from the OS
  • Partial support for VB.NET and F# – Microsoft and the community continue to work on this but it’s not yet 100%

Developers Should Use .NET Framework When…

.NET Framework is distributed with Windows. Generally, it is used to build Windows desktop and large-scale enterprise applications using .NET workflow and data connection tools.

The .NET Framework provides services that include:

  • Memory management
  • Type and memory safety
  • Security
  • Networking
  • Application deployment
  • Data structures
  • APIs

.NET Framework can be used with Docker and Windows Containers and is most feasible when:

  • It is already being used – Instead of migrating, extend the application. For example, developers can write a new web service in ASP.NET Core
  • You’re using third-party libraries or NuGet packages not available in .NET Core – Despite .NET Core’s popularity, you’ll need to use the .NET Framework when working with libraries that aren’t compatible with .NET Core. NuGet is the free and open source package manager for .NET and other Microsoft development platforms. The NuGet ecosystem includes client tools that provide the ability to produce and consume packages. It also has a central package repository for package authors and consumers. It is available as a Visual Studio extension
  • You’re using technologies not yet available in .NET Core – .NET Core does not support all .NET Framework technologies. These not-yet-available technologies include:
    • ASP.NET Web Forms applications (no plans to port)
    • ASP.NET Web Pages applications (plans to port)
    • ASP.NET SignalR server/client implementation (plans to port)
    • WCF services implementation (no plans to migrate, but it is being considered)
    • Workflow related services (no plans to port) including Windows Workflow Foundation (WF), Workflow Services (WCF + WF in a single service), and WCF Data Services (formerly known as “ADO.NET Data Services”)
    • Windows Presentation Foundation (WPF) and Windows Forms (no plans to port)
  • The platform does not support .NET Core – Again, not all Microsoft and third-party platforms support it, such as some of Azure’s services. You may encounter some issues even with supported services, which comes with the territory. With .NET Core increasingly gaining traction, it’s becoming easier to find tutorials and workarounds for issues you may encounter. For instance, we encountered a 502.5 Process Failure when trying to start an Azure App Service. So, we published a post offering guidance for others who encounter the same issue

When Not to Run .NET Framework

There are also a few situations in which you shouldn’t run the .NET Framework. These include when:

  • Multiple OS platforms are required
  • High performance and scalability are needed
  • .NET Core works
  • Open source framework is required

How to Port from .NET Framework to .NET Core

If and when you decide to migrate your .NET Framework to .NET Core, follow these steps (after a proper assessment, of course):

1. Analyze Third Party Dependencies

More than just knowing what the third-party dependencies are, you need to understand how the application functions with the third-party dependencies that run on .NET Core. You also need to be aware of what needs to be done if they do not run.

NuGet packages are easy to check plus the package has a set of folders for each platform. You can also look for a folder or entry on the Dependencies page with any of the following names:

netstandard1.0
netstandard1.1
netstandard1.2
netstandard1.3
netstandard1.4
netstandard1.5
netstandard1.6
netcoreapp1.0
portable-net45-win8
portable-win8-wpa8
portable-net451-win81
portable-net45-win8-wpa8-wpa81

If the dependencies are not NuGet packages, the ApiPort tool can check the portability of the dependency.

Since .NET Core 2.0, a compatibility shim allows referencing .NET Framework packages that haven’t been switched to use .NET Standard. Be sure to thoroughly test these packages as they may still have issues if they use unsupported APIs.

2. Target the .NET Standard Library

The .NET Standard library is intended to be available on all .NET runtimes. So, targeting the .NET Standard library is the best way to build a cross-platform class library.

There are multiple versions to consider that are available to varying degrees across eight platforms. If a project targets a lower version, it cannot reference a project that targets a higher version. Pick the lowest possible .NET Standard version to use across all projects. Below is a chart with each .NET Standard version that shows the specific areas they run on:

Screenshot via Microsoft.com

3. Retarget Projects

All the projects to be ported need to be targeted to .NET Framework 4.6.2. This will ensure API alternatives for .NET Framework specific targets can be used for non-supported APIs.

This is done easily in Visual Studio with a “Target Framework” command and recompiling the projects.

4. Port Tests Code

Porting code to .NET Core is a significant change; testing is strongly encouraged. Use a suitable testing framework such as:

With tools like xUnit, it’s possible to use templates and edit them to write .NET Core tests. Here’s an example of an edited .csproj file:

<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFramework>netcoreapp1.1</TargetFramework>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="xunit" Version="2.3.0-beta2-build3683" />
<DotNetCliToolReference Include="dotnet-xunit" Version="2.3.0-beta2-build3683" />
</ItemGroup>

</Project>

5. Execute the Porting Plan

The best way to port the code depends on how the framework is structured. But breaking the code base into steps and layers should work well. Here is how to do it:

  1. Identify the “base” of the library. This base could be the data models or classes and methods that everything else needs to use
  2. Copy the base into a new .NET Core project
  3. Make any changes needed to compile the code
  4. Copy another layer of code and repeat

Then There is Xamarin

Xamarin may sound like a new prescription medication. However, Xamarin is a platform for developing apps that run on iOS, Android or Windows Phone devices.

Xamarin is written in C# and available in all editions of Visual Studio.

Microsoft promises that Xamarin is the best way to create a user interface (UI) and optimize performance in apps on multiple platforms. This is important today when apps need to run on at least iOS and Android devices.

Xamarin shares code across platforms and uses a single technology stack to decrease time to market and engineering costs. But user interface-intensive apps may need more platform-specific coding. The amount of code sharing and savings then decreases.

More .NET Platforms on .NET Standards

In addition to .NET Framework, .NET Core and Xamarin, .NET Standards also supports the following platforms:

  • Mono – An open-source .NET created before Xamarin and Microsoft collaborated. It is based on the ECMA standards for C# and the Common Language Infrastructure. In addition to C#, developers can use VB 8, Java, Python, Ruby, Eiffel, F# and Oxygene
  • Universal Windows Platform – Software platform created by Microsoft to help develop apps that run on Windows 10, Windows 10 Mobile, Xbox One, IoT and Hololens devices. Developers can use C++, C#, VB.NET and XAML
  • Windows – versions 8.0 and 8.1 are supported
  • Windows Phone – Windows Phone was primarily developed for the consumer market and replaced by Windows 10 Mobile in 2015
  • Windows Phone Silverlight – The deprecated application framework was designed to run internet applications and compete with Adobe Flash

All these platforms will implement .NET Standards – a common set of APIs that replace portable class libraries (PCLs). This ensures code sharing across desktop applications, mobile apps, mobile games and cloud services.

It’s important to always have a good APM in place for your .NET application. Retrace is a great full lifecycle option that you can try for free.

You can also try Netreo’s free code profiler Prefix to write better code on your workstation. Prefix works with .NET, Java, PHP, Node.js, Ruby and Python.

]]>