Monday, February 26, 2024

Dall-E3 Advanced Prompts Guidelines

 



Recently, OpenAI had recently released Dall-E3, a great improvement over the Dall-E2 image generator. You may have used it and generated some images using simple text prompts. The real "art" in this game is understanding prompt and how to design it to get accurate results.


The image at the top of this blog was generated using the prompt:


a photo of Salvador Dali drawing on a screen of a laptop


While it is a nice image, I had a different idea in mind when supplying the prompt. How can we create a better prompt that will generate the image we've had in mind?

The general guideline is to split the prompt to multiple statements, each statement adding more requirement to the image generator, for example:


Main object: The main object is the artist Salvador Dali. Behavior: Salvador Dali is painting a cute puppy on a laptop. Environment: The artist is located in an artist studio room. Items: There will be various painting related items spread in a mess around in the room. These items include: colors palette, colors buckets, various brushes in different size. Add additional painting related tools. Colors: Use brownish and yellowish background colors


And the result is:




We can see a great improvement, though still not perfect, the image generator is starting to get the idea we have in mind. Now that we have the right concept, we can add more statements, or update the existing statements as if we're programming a multiple layers application.

Let's give it another try:


Main object: The main object is the aritst Salvador Dali. Behavior: Salvador Dali stands and draws a cute puppy on a laptop. Environment: The artist is located in an artist studio room. Items: There will be various painting related items spread in a mess around in the room. These items include: colors palette, colors buckets, various brushes in different size. Add additional painting related tools. Colors: Use brownish and yellowish background colors Point of View: The point of view is diagonal for the top right side toward the bottom left direction.


And this time, we're almost there:




Now a final touch:


Main object: The main object is the artist Salvador Dali. Behavior: Salvador Dali stands and draws a drawing of cute puppy on a big laptop. Body language: Salvador Dali's face expression is very busy. Environment: The artist is located in an artist studio room. Items: There will be various painting related items spread in a mess around in the room. These items include: colors palette, colors buckets, various brushes in different size. Add additional painting related tools. Colors: Use brownish and yellowish background colors Point of View: The point of view is diagonal for the top right side toward the bottom left direction. We can see both Salvador Dali's face and the laptop




Monday, February 19, 2024

New Software Project: Steps and Architecture



In this post, we'll outline the steps needed to initiate a new software project. While these steps may not be applicable to all project types, they encompass details relevant to most software projects. Having a clear understanding of these steps from the outset can enhance our progress and help prevent costly mistakes that may arise if discovered later in the implementation stage.


Use a kubernetes architecture

Every contemporary software project should be built upon a Kubernetes architecture, offering numerous significant benefits. Firstly, Kubernetes provides a comprehensive framework for addressing various software challenges including scaling, upgrades, storage management, log handling, and load balancing. Moreover, once a project is configured for Kubernetes, it becomes compatible with both bare metal Kubernetes setups and any major cloud provider platforms.

Use an easy scaled DBMS

Traditionally, software relied on relational database management systems (DBMS) for their support of complex data processing via SQL. However, these systems have significant drawbacks, particularly in terms of cluster support and scalability. While major cloud providers offer built-in solutions for such DBMS, like AWS RDS, it's advisable to consider alternative, simpler DBMS for ongoing project activities, such as Redis or MongoDB. These lightweight DBMS provide easier cluster support and scalability.

Implement CI/CD from day 1

Integration of CI/CD should be prioritized right from the inception of your project rather than waiting until the deployment phase in production. By integrating Continuous Integration and Continuous Deployment (CI/CD) practices from day one, you establish a foundation for efficient project management and development. This comprehensive approach encompasses not only the seamless build, test, and deployment processes but also facilitates early detection of potential issues and ensures consistent quality throughout the project lifecycle. Embracing CI/CD early on sets the stage for streamlined development workflows and enables rapid iteration and delivery of software updates, ultimately enhancing project agility and resilience.

Enable desktop based system

While CI/CD remains a cornerstone of modern software development, it's equally imperative to conduct thorough local testing on your machine for expedited bug detection and feature iteration. The ability to build and run the project locally on your desktop is invaluable for accelerating development cycles and ensuring rapid feedback. To achieve this seamless local development experience, it's essential to develop scripts that automate the local build and deployment processes, streamlining testing and validation efforts. Kubernetes emerges as a highly recommended solution, providing a robust framework for orchestrating containerized applications and enabling efficient local deployment. Moreover, adopting Helm-based configuration not only simplifies management but also optimizes resource utilization, ensuring that the system operates efficiently even in local development environments. By prioritizing local testing and leveraging Kubernetes alongside Helm, developers can achieve faster development iterations, smoother testing workflows, and ultimately deliver higher-quality software solutions.

Identify performance bottlenecks

In the realm of software development, striking a delicate balance between crafting clear and simple code while ensuring optimal speed and performance is paramount. Generally, it's advisable to prioritize the development of code that is transparent and straightforward, deferring performance optimizations until later stages, typically after rigorous stress testing has been conducted. However, the role of the system architect is pivotal in this regard. It's incumbent upon them to proactively identify potential performance bottlenecks early in the project's lifecycle.

Anticipating these bottlenecks allows architects to integrate specialized treatments and optimizations into the system's design from the outset. By doing so, they lay a robust foundation that mitigates the risk of performance issues arising later in the development process. This proactive approach is critical because rectifying performance deficiencies at a later stage may necessitate extensive architectural revisions, potentially leading to project delays or, in the worst-case scenario, requiring a complete overhaul.

Therefore, while it's prudent to prioritize simplicity and clarity in code implementation, it's equally crucial for architects to engage in forward-thinking and strategic planning to address potential performance challenges preemptively. By doing this, development teams can minimize the risk of encountering significant hurdles during the stress testing phase, ensuring a smoother and more efficient project lifecycle overall.

Use project tests

See this post.

Use internal management GUI

It's important to differentiate between the end user graphical user interface (GUI) and the internal management GUI within a project. While the end user GUI focuses on providing a user-friendly interface for external users, the internal management GUI serves developers and system administrators, offering a robust set of functionalities without necessarily prioritizing visual aesthetics. This internal interface enables developers to efficiently manage and monitor the system, incorporating various tools and features tailored to their needs.

Moreover, the internal management GUI can include data visualization views, providing a clear depiction of the system's performance and success in achieving its objectives. These visualizations offer valuable insights into system metrics and status, facilitating informed decision-making and troubleshooting.

By distinguishing between these two interfaces and prioritizing functionality over visibility in the internal management GUI, development teams can streamline their workflow and enhance the efficiency of system management and monitoring processes. See this post for more.

Run Stress Tests

Regular stress testing, either periodically or as part of the CI/CD pipeline, is essential to gauge how well a system performs under anticipated loads. These stress tests should quantify the expected operational costs of running the system under predefined levels of load. To effectively analyze stress test results and gain actionable insights, it's crucial to utilize monitoring tools such as Prometheus and Grafana.

By integrating Prometheus and Grafana into the testing framework, teams can visualize key performance metrics and identify potential bottlenecks or areas for optimization. It's worth noting that relying solely on CPU and memory metrics may not provide a comprehensive understanding of system performance. Therefore, it's advisable to augment these metrics with custom Prometheus counters embedded within the microservices of the project. These custom counters can capture additional application-specific information and statuses, offering a more nuanced view of system behavior during stress testing.

By leveraging Prometheus and Grafana in conjunction with custom counters, teams can gain a holistic understanding of system performance under varying loads, enabling informed decision-making and proactive optimization efforts. See also this post for more details.

Documentation Practices

Effective documentation practices are essential for ensuring clarity, maintainability, and scalability throughout the software project lifecycle. Comprehensive documentation serves as a valuable resource for developers, stakeholders, and end-users alike, facilitating understanding and promoting successful project outcomes. Here are some key aspects to consider when establishing documentation practices:

Code Comments: Do not use code comments, unless you do something which is not clear, and has a hidden meaning.

API Documentation: Documenting APIs (Application Programming Interfaces) is crucial for enabling seamless integration and interoperability between different components of the system. API documentation should include endpoint descriptions, request/response formats, authentication methods, and usage examples to guide developers in utilizing the API effectively. A good way to handle this is using swagger.


Monday, February 12, 2024

NATS Monitoring Using Prometheus/Grafana


In a recent post we've setup a NATS cluster in kubernetes. In this post, we will review the steps to monitor NATS using Prometheus and Grafana.


The prometheus counters for NATS monitoring are provided using an exporter. This is implemented as a sidecar - an additional container in each pod which pulls the monitoring data from the local pod NATS container, and exposes an HTTP endpoint for prometheus.


The Exporter

To implement an exporter we create a minimal GO program to run the NATS exporter. The exporter uses localhost address, as it is part of the same pod.


package main

import (
"github.com/nats-io/prometheus-nats-exporter/exporter"
)

func main() {
opts := exporter.GetDefaultExporterOptions()
opts.ListenAddress = "0.0.0.0"
opts.ListenPort = 8080
opts.GetVarz = true
opts.NATSServerURL = "http://localhost:8222"

natsExporter := exporter.NewExporter(opts)
err := natsExporter.Start()
if err != nil {
panic(err)
}
natsExporter.WaitUntilDone()
}


The Sidecar

To use a sidecar, we add an additional container after the 2 existing ones.



The Scraping

To enable scraping of the pod by prometheus, we add the related annotations to the template section of the NATS statefulset.


template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/path: "/metrics"
prometheus.io/port: "8080"


The Grafana Dashboard

Last, we import a pre-made example dashboard from here.

Notice that the dashboard displays absolute values, while in real life you will probably want to change it to use rate, for example, change this:

gnatsd_varz_in_bytes[1m]

to:

rate(gnatsd_varz_in_bytes[1m])