When an SBOM becomes operationally useful: lessons from Eclipse Kura
Supply chain security has become a critical topic in the security world in recent years, and while SBOMs are a foundational piece, they are still infrequently generated and even less frequently used in a way that meaningfully improves software supply chain security.
To address this gap, the OCX session “Generating SBOM: Understanding the Why, Mastering the How and Learning from Eclipse Kura’s Experience” focuses on simplifying SBOM adoption through a combination of practical resources and real-world project experience. Drawing on the Eclipse Foundation’s security tooling and guidance, Ioana Iliescu, Security Team Tech Lead at the Eclipse Foundation, and Mattia Dal Ben, Principal Software Engineer and Eclipse Kura committer, walk through how SBOM generation, supporting infrastructure, and automation come together in practice, based on Eclipse Kura’s adoption journey.
SBOMs are often introduced through compliance or customer-driven requirements. When their value is perceived as external rather than operational, teams struggle to prioritise the initial effort required for meaningful adoption. As Ioana Iliescu explains:
When the benefit feels like it’s external, and delayed, but the cost is internal, and immediate, SBOMs tend to lose out to feature work.
The consequences of this deprioritisation become visible when a vulnerability is disclosed. At that point, teams must rely on the information they already have about their software composition. As Iliescu notes, traditional dependency management reflects intent rather than reality:
It’s what the project declares itself that it depends on, and SBOM shows what’s actually shipped, including not only direct, but also transitive dependencies, and the relationship between them.
This visibility into transitive dependencies directly affects how quickly teams can assess exposure and respond to software supply chain incidents.
Eclipse Kura’s experience also shows that SBOM generation on its own is not sufficient to create security value. As Mattia Dal Ben points out:
SBOM generation is a small piece of the overall picture. You have to generate them automatically, keep them updated, store them, ingest them, and perform continuous analysis on them.
Integrating SBOM generation into existing build systems and CI/CD pipelines required addressing compatibility issues and project-specific edge cases, even with a mature SBOM tooling ecosystem.
Attendees of this session will gain a concrete understanding of what it takes to generate and move SBOMs from static artefacts into operational security inputs. The talk will walk through tooling choices, integration decisions, and edge cases encountered in Eclipse Kura, alongside the Eclipse Foundation infrastructure that supports SBOM generation, storage, and analysis at scale.
Learn more at OCX in Brussels
Register and attend this session in Brussels to see how SBOMs are operationalised in practice, based on real Eclipse Foundation infrastructure and the Eclipse Kura team’s experience.
In October 2021, Facebook disappeared from the internet for roughly six hours.
Its core platforms — Instagram and WhatsApp — went down with it. For many users it felt like an unusually long outage. For businesses, it meant lost revenue. For engineers, it exposed something more structural: how centralized modern internet infrastructure has become.
This wasn’t a breach. It wasn’t ransomware. It wasn’t a nation-state attack.
It was a routing failure.
What Actually Happened
The root cause was a configuration change affecting BGP (Border Gateway Protocol). BGP is how networks announce their IP prefixes to the rest of the internet. When Facebook’s routes were withdrawn, its IP space effectively disappeared from global routing tables.
No routes → no traffic.
DNS servers became unreachable. Domain names stopped resolving. Internal tools that relied on the same infrastructure went down. Even physical access systems reportedly failed because they depended on the internal network.
This is a critical point: the systems required to fix the outage were partially affected by the outage itself.
That’s not a dramatic failure. It’s a coupling problem.
When a Company Becomes Infrastructure
Facebook is not just an app. It functions as:
an identity provider
an advertising platform
a storefront for small businesses
a messaging backbone in many countries
When such a platform fails, the impact extends beyond its own users. It affects commerce, media distribution, authentication workflows, and customer support pipelines.
The outage highlighted a broader issue: private platforms increasingly act as public infrastructure.
Centralization increases efficiency.
It also increases blast radius.
Tight Coupling at Scale
Large platforms optimize for integration. Shared identity systems, shared networking layers, shared operational tooling — all of it improves speed and coordination.
But integration also creates shared failure domains.
When external routing fails and internal tooling depends on the same routing layer, recovery becomes slower and more complex. Redundancy inside one organization is not the same as independence across systems.
This is the architectural trade-off centralization often hides.
Why Scale Doesn’t Eliminate Fragility
Large tech companies invest heavily in reliability engineering. They measure uptime in decimals. They build multiple data centers across continents.
Yet high availability percentages don’t eliminate systemic risk. They reduce average downtime — but they don’t necessarily reduce the impact of rare failures.
When billions of users rely on a single entity, even statistically rare events become globally disruptive.
Resilience isn’t just about uptime.
It’s about limiting the scope of failure.
The Centralization Trade-Off
It’s easy to frame centralization as purely negative, but that would be simplistic.
Centralized systems offer:
simpler identity management
unified moderation
cost-efficient global scaling
consistent user experience
The problem isn’t centralization itself. It’s unexamined dependency.
Users and businesses optimize for convenience. They rarely evaluate systemic risk when choosing platforms. The risks become visible only when something breaks.
The 2021 outage briefly made that trade-off visible.
Is Decentralization the Answer?
After major outages, discussions about decentralization resurface. Federated networks, distributed architectures, blockchain systems — alternatives appear attractive.
But decentralization alone doesn’t guarantee resilience. Without operational discipline and independent governance, control can simply recentralize around infrastructure providers or protocol maintainers.
Distribution reduces certain risks.
It introduces others.
Architecture still matters.
The Structural Lesson
Complex systems fail. That’s inevitable.
The key question is not whether failure happens — it’s how far failure propagates.
When authentication, communication, and commerce converge inside a handful of companies, outages become systemic shocks. The internet may look decentralized on the surface, but power and dependency are increasingly consolidated.
The Facebook outage wasn’t just downtime. It was a reminder that integration and efficiency often come at the cost of optionality.
And optionality is a core component of resilience.
I write about infrastructure risk, privacy, system design trade-offs, and long-term software resilience at:
https://50000c16.com/
If you’re building systems that millions depend on, centralization isn’t just a business decision — it’s an architectural responsibility.
Compose profiles let you group services so you can start only a subset of your stack for specific scenarios (e.g., lightweight testing vs. full production).
In your docker-compose.yml, add a profiles list to each service you want to group:
docker compose up (no --profile)
Starts only services without a profiles key.
In the example above, nothing would start unless you define a default (non-profiled) service.
docker compose --profile core up
Starts only services tagged with core (postgres, jobrunner).
Ideal for a lightweight testing stack.
docker compose --profile full up
Starts only services tagged with full (nextjs, authserver).
Multiple profiles are supported:
docker compose --profile core --profile full up
This allows you to maintain one Compose file while running minimal stacks for testing or the full environment as needed.
If a service should always run, omit the profiles key. It will start regardless of profile flags.
Multiple Databases and Profiles
Docker Compose does not allow multiple services with the same name—even across different profiles.
If you need both a production database and a unit test database, give them unique service names and assign each to its own profile:
Your application containers use one DATABASE_URL at a time.
Each profile startup determines which database the app connects to.
For example:
In a test profile, set DATABASE_URL to unit-test-db.
In a prod profile, set DATABASE_URL to app-db.
There is no runtime toggling — each profile spin-up decides which database your app connects to based on the environment variables provided at startup.
Alternative Approach
Instead of profiles, you can maintain separate Compose files:
docker-compose.test.yml
docker-compose.prod.yml
Each file can hardcode the correct database host.
This provides clearer separation but requires maintaining multiple files.
In Object-Oriented Programming (OOP), two of the most important concepts are:
Instance Variables
Instance Methods
If you don’t understand these properly, OOP will always feel confusing.
So let’s break everything down step by step in the simplest way possible.
Let’s Start with a Simple Real-Life Example
Imagine a classroom. Learn How Instance Variables and Methods Actually Work in Python
You (teacher) are the class blueprint.
Your students are objects.
Every student:
Has a name
Has a roll number
Has marks
Can perform actions (submit homework, give test, etc.)
Now here’s the important part:
Even though all students come from the same class,
each student has their own data.
That “own data” is exactly what we call:
Instance Variables
And the actions they perform?
Instance Methods
What is an Instance Method in Python?
An instance method is a method that belongs to an object and works on that specific object.
Definition (Simple Words)
An instance method:
Is defined inside a class
Has self as its first parameter
Can access and modify instance variables
Why Do We Need self?
When we create multiple objects from a class, each object has its own data.
self tells Python:
Work with the current object that is calling this method
Example
classUser:defactivate(self):self.is_active=True
If we create two objects:
user1=User()user2=User()
When we call
user1.activate()
Python automatically does this internally:
User.activate(user1)
That means:
self = user1
So instance methods always operate on the object that calls them
What is an Instance Variable in Python?
An instance variable is a variable that belongs to a specific object.
It is created using:
self.variable_name=value
Important Concept
Instance variables:
Store data
Are unique for each object
Exist inside the object
Can be different for different objects Example
defset_email(self,email):self.email=email
When we call:
user1.set_email("shameel@hasabtech.com")
It becomes:
user1.email="shameel@hasabtech.com"
Now email belongs only to user1.
If we check user2, it still does NOT have email until we set it.
That is why instance variables are object-specific.
Complete Example with Deep Explanation
Let’s build a proper example and understand what happens step by step.
classUser:defactivate(self):self.is_active=Truedefdeactivate(self):self.is_active=Falsedefset_email(self,email):self.email=emaildefshow_status(self):print(f"{self.email} is {'active'ifself.is_activeelse'not active'}")
Step 1: Creating Objects (Instances)
user1=User()user2=User()
When we execute this:
Python creates two separate objects in memory
Each object has its own space to store data
Both objects have access to all instance methods
Important: Object and Instance mean the same thing.
What Happens Inside Memory?
Even though both objects come from the same class blueprint:
user1 has its own data storage
user2 has its own data storage
They do NOT share instance variables.
This is the beauty of OOP.
Understanding Instance Methods in Action
Now let’s call:
user1.set_email("shameel@hasabtech.com")
What happens?
Python sees user1
It passes user1 automatically as self
Inside method:
self.email=email
Becomes
user1.email="shameel@hasabtech.com"
Now:
user1 has email
user2 still has nothing
This proves instance variables belong to objects.
Adding More Data to Objects
Now:
user1.activate()user2.deactivate()
This creates:
user1.is_active=Trueuser2.is_active=False
Again:
Each object has its own is_active
They are completely independent
This independence is the core idea of instance variables.
Why Methods are Called Instance Methods?
Because they:
Work with instance variables
Depend on the object
Use self to access object data
For example:
defshow_status(self):print(f"{self.email} is {'active'ifself.is_activeelse'not active'}")
This method:
Reads self.email
Reads self.is_active
Prints data of that specific object
So this method behaves differently for each object.
That’s why it is called an instance method.
Common Beginner Confusion
Many students think:
Is self a keyword?
No.
self is just a naming convention.
You can write:
defactivate(myobject):
def activate(myobject):
But by convention, we always write self
Why This Concept is Very Important?
If you understand instance variables and instance methods, you can:
Build login systems
Create user management systems
Understand Django models
Work with APIs
Design real-world applications
Without understanding self, OOP will feel complicated.
Final Understanding
Whenever:
You attach data using self → It becomes an instance variable.
You define a method with self → It becomes an instance method.
Each object:
Has its own data
Shares method structure
Behaves independently
Summary
Object = Instance. They mean the same thing.
Instance Variables are the “adjectives” (data) that describe the object.
Instance Methods are the “verbs” (actions) the object can perform.
self is the bridge that connects the method to the specific object’s data.
Each object has its own copy of instance variables
Stay connected with hasabTech for more information:
Website | Facebook | LinkedIn | YouTube | X (Twitter) | TikTok
Type: INVENTION Domain: Research Engineering Date: 2/20/2026
🎯 Potentiel
Réduction du taux d’échec des inventions publiées via gating quantifié (objectif: -50% erreurs / -70% répétition).
📋 Description
Invention guidée par signaux web: le focus est “Intelligence Artificielle”. Plutôt que du buzzword bingo, l’objet est un cadre reproductible qui force une preuve (PoC + baseline + métriques) avant de publier. Les concepts (Energy conservation, Genetic algorithms, Zero-sum games) servent à définir des fonctions d’impact/risque et une dynamique d’amélioration.
🧭 Analyse de la concurrence (pré-publication)
Sujets fréquents: AI Models, theoretical physics, ai safety, social science, engineering, product updates
🔬 Concepts Sources
Energy conservation
Genetic algorithms
Zero-sum games
🚀 Implémentation Proposée
Définir un baseline mesurable lié à “Intelligence Artificielle”
Écrire un prototype minimal (fonctionnelle, instrumentation incluse)
Évaluer sur un jeu de tests/simulateur (3 scénarios minimum)
Comparer baseline vs prototype et calculer delta
Décider publication seulement si delta est prouvé
Généré par Lazarus Prometheus – Curiosity Drive Legacy Score: 10/12
At JetBrains, we aim to make Kotlin development as accessible and efficient as possible across the entire ecosystem. While IntelliJ IDEA remains the premier IDE for Kotlin, we recognize that many developers use Visual Studio Code for a variety of tasks and projects.
To help streamline the transition from Java to Kotlin for VS Code users, we are pleased to introduce the Java to Kotlin (J2K) converter extension.
Download the Extension
Seamless Conversion in VS Code
This new extension allows you to convert individual Java files into Kotlin code with a simple context menu action, significantly reducing the manual effort required when migrating legacy codebases or switching languages mid-project.
Because the extension leverages the same underlying engine used in our primary IDEs, you can expect a reliable conversion that respects Kotlin idioms and syntax requirements.
See it in action
The converter is designed to be unobtrusive and easy to use. Watch the short demo below to see how it handles the conversion process.
How to get started
To begin using the converter, simply:
Install the Java to Kotlin Converter extension from the Visual Studio Marketplace.
Open any .java file in your workspace.
Right-click anywhere in the editor or on the file in the Explorer and select Convert to Kotlin.
Our Commitment to the Ecosystem
This extension is part of our ongoing effort to support Kotlin users wherever they choose to write code. It joins other initiatives aimed at improving the developer experience outside of IntelliJ IDEA, such as the Kotlin LSP, which provides IDE-independent language support via the Language Server Protocol.
As this is a new release, we highly value your feedback. If you encounter any issues or have suggestions for improvements, please report them on YouTrack or through the extension’s marketplace page.
Today we’re rolling out another bug-fix update for your TeamCity 2025.11 On-Premises servers. This update addresses a number of issues, inlcuding:
QoL updates for the bundled IntelliJ Platform Plugin;
Variable GID value for Docker inside TeamCity Docker images;
NPE login fails;
Connection settings are reset after changing the parent project.
All TeamCity bug-fix updates include performance and security improvements, so we recommend that you never skip these minor updates. See TeamCity 2025.11.3 Release Notes for the complete list of resolved issues.
Why update?
Staying up to date with minor releases ensures your TeamCity instance benefits from the following:
Performance improvements.
Better compatibility with integrations.
Faster, more stable builds.
Enhanced security for your workflows.
Compatibility
TeamCity 2025.11.3 shares the same data format as all 2025.11.x releases. You can upgrade or downgrade within this series without the need for backup and restoration.
How to upgrade
Use the automatic update feature in your current TeamCity version.
Download the latest version directly from the JetBrains website.
Pull the updated TeamCity Docker image.
Need help?
Thank you for reporting issues and providing feedback! If you have questions or run into any problems, please let us know via the TeamCity Forum or Issue Tracker.
Let’s call a spade a spade. Some enterprises are already using AI agents, but very few can explain their impact on business performance.
Metrics such as DORA, SPACE, and developer experience indicators captured through third-party platforms offer insight into delivery velocity and developer quality of life, but it is still difficult to cleanly map this all the way to business impact.
Unless you work directly on model development, model metrics themselves rarely determine whether AI is creating enterprise value.
The gap between technical performance signals and sustained business outcomes is an obstacle to scaling AI responsibly.
From technical metrics to business value
Abstract benchmarks such as SWE-Bench Pro and Tau2-bench are directionally useful in selecting AI tools, but can be orthogonal to how these tools perform in enterprise systems. An agent that performs well in a controlled environment can fail once integrated into production workflows. What matters is not benchmark scores, but the impactfulness, traceability, and resilience of AI systems under real-world conditions.
Recent data underscores the urgent need to find an accurate way of measuring these variables. Though 88% of employees use AI at work today, just 5% use it “in a transformative way”, according to the EY 2025 Work Reimagined Survey.
Blindly adopting AI is unlikely to be fruitful. Enterprises should instead experiment with and evaluate AI through operational metrics on the systems they are accountable to build and operate. The focus should be on the lifetime cost of maintaining systems, the average time humans spend over baseline, and throughput as a function of Total Cost of Ownership (TCO).
Auditability matters for tracing decisions and meeting governance needs, while human readability ensures teams can understand and manage system behavior now, and later. These are table stakes for technical teams to have in place as they adopt AI at scale.
The ROI problem
Every enterprise wants to link AI to ROI, but the data rarely aligns. The problem is not limited to model telemetry. AI is embedded into enterprise systems and assigned responsibility for specific parts of the SDLC and operational workflows.
Evidence of its impact must therefore span system behaviour, human intervention, and downstream business KPIs. These signals live in different systems and move on different timescales, which creates a gap between AI activity and measurable business outcomes. This is why most organizations rely on proxies or assumptions rather than proof.
Closing the gap
The next generation of AI orchestration platforms will need to close this gap by correlating technical performance with operational and financial signals. When those systems mature, ROI will shift from being an abstract target to a measurable outcome grounded in data.
The impact of this gap is already visible in enterprise outcomes. The WRITER 2025 Enterprise AI Adoption Report found that organizations without a formal AI strategy report only 37% success when adopting AI, compared with 80% for those that tie performance to clear operational outcomes.
The data is unambiguous. Only when an organization measures technical and operational signals together does it finally gain a true picture of AI’s value.
Towards continuous benchmarking
What underlies enterprise AI is not static. Data drifts, workflows evolve, and compliance obligations expand. Measurement must therefore become a continuous feedback loop rather than an annual report.
The same principle should apply across the enterprise: Performance metrics should remain stable, but they must either stay independent of changing conditions or explicitly measure those changes over time.
Measuring what matters
Meaningful AI performance measurement is not about bigger numbers or more dashboards. It is about connecting operational signals with business truth.
Enterprise leaders must grapple with model performance alongside how intelligently it scales, how transparently it operates, and how clearly its impact can be proven.
Taking benchmark numbers at face value resembles trusting a car manufacturer’s fuel efficiency without ever driving the car to see if it holds up in real conditions.
Only when these can be addressed with real data will AI become a truly accountable part of the enterprise stack.
The real question for leaders is simple: Are you measuring the numbers that prove AI is working in practice, or just parroting back the numbers on public benchmarks?
Learning to code in an online course can feel like hitting a wall again and again, without much help moving forward. Our research team wanted to change that. That’s why our Education Research team built an AI-powered hints tool that doesn’t just point out errors but helps students understand them. As described in our blog post last summer, students can use the tool in JetBrains Academy courses to get tailored guidance nudging them towards the solution instead of staring blankly at a stubborn piece of code or waiting for help on a forum.
Try our plugin
Since then, our researchers have investigated how students actually use the tool and published the results in a paper that they will present at the Technical Symposium on Computer Science Education (SIGCSE TS) February 19 in St. Louis, Missouri. In this blog post, we will explain how the study was set up, its results, and our analysis.
Learning to code with the help of smart feedback
In the last post, we covered the history of online learning and the importance of feedback in any type of learning environment. Online programming courses can differ a lot in format, especially in how they encourage students to practice writing and running code within the course.
Many online learning platforms, such as Udemy, Codecademy, and edX, provide online editors for students to complete the exercises. Learning programming inside a code editor is easier than installing and learning new software, but in the long run it means that the student is unfamiliar with the relevant professional environment. Other platforms, such as Hyperskill, offer a hybrid option, where the student can also learn in a professional integrated developer environment (IDE) if they choose to do so. The downside of a hybrid course is that some students might not choose to use the IDE, for example if they consider it a hurdle to install and learn to navigate new software.
For our JetBrains Academy courses, we released the JetBrains Academy plugin a few years ago, which lets educators build complete courses directly inside the IDE. With this setup, students can read theory and immediately apply it by solving practical tasks in the very same environment they use to write code. As a result, they can become comfortable working in IDEs early on and are better prepared for real-world software development roles.
A recent addition to our plugin is the AI-powered hints tool, developed by our Education Research team. The tool leverages powerful IDE features by combining static analysis and code quality checks with LLMs to provide personalized hints to students. In the previous paper, we conducted evaluation studies to gauge how useful students found the tool while learning, as described in the previous blog post.
To help students even further, we wanted to know more about how they are really interacting with the tool and discover possible new behavior patterns. In the rest of this blog post, we will talk about exactly this: how students are actually interacting with the AI-powered hints tool.
Smart feedback in online learning
Recent years have seen many studies exploring how students interact with intelligent tutoring systems, offering useful directions for future system design. In this short subsection, we will provide a summary of recent studies, plus describe what our study adds to the field.
Researchers in this study examined an intelligent next-step hint system to understand why students ask for help, looking at factors such as time elapsed and code completeness after each hint, and identifying reasons like difficulty starting an exercise. This work provides general insights into students’ hint-seeking patterns, but without the details (e.g. keystroke data). This study analyzed when and how to provide feedback and hints using keystroke datasets annotated with points where experts would intervene, but did not look at students’ actual interactions with hint systems.
In this paper, researchers investigated how different hint levels support task completion and why students request hints, using a think‑aloud study with pre‑ and post‑tests for 12 students. However, we would have liked to see broader usage patterns or how learners cope with unhelpful hints.
More recently, researchers studied how students use on-demand automated hints in an SQL course and how these hints affect learning, using A/B testing to identify behavioral differences and simple patterns. For example, they found that students often request a second hint within 10 seconds of the first one. While this research sheds light on basic behavioral trends, it mainly asks whether adding a hint system supports learning, rather than closely examining the interaction patterns themselves.
Overall, prior work has focused on why and when hints are given, but far less on how students actually work with them in practice. In our study, we applied process mining techniques to uncover detailed behavioral patterns in how students interact with hints while they solve programming tasks. In addition, we conducted interviews with a subset of the students to learn more about how they interact with the hints tool in specific scenarios.
Our investigation into students’ behavioral patterns
With our study, we wanted to better understand how the students are really interacting with the tool, as well as how students navigate situations with less helpful hints. Specifically, our two research questions were:
What behavioral patterns can be identified based on students’ interaction with the next-step hint system?
What strategies do students use to overcome unhelpful hints?
Our study collected data in two steps. First, we collected information about all of the students’ interactions with the hints system, analyzing these interactions quantitatively. Then, we selected a subset of six students to interview for about 30 minutes, so that we had a qualitative and in-depth complement to the quantitative analysis. In the next subsection, we will tell you about the methodology for each step. The subsection after that will present the results and analysis.
Quantitative behavioral analysis
For the first part of the study, we analyzed detailed problem-solving data from first- and second-year Bachelor’s students working on programming tasks in our introductory Kotlin course. The selected projects represent different levels of complexity and cover basic topics such as variables, loops, conditional operators, and functions. The 34 participants had previously completed at least one programming course in another language, and they had no experience with Kotlin before. We asked these students to complete three projects from the course, using the hint system whenever they wanted.
We used KOALA to capture keystrokes, IDE actions, the windows they accessed, and rich information about their hint usage. Hint-usage information included details like when hints were requested and for which specific tasks. The resulting dataset contains:
6,658,936 lines of code
1,364,943 IDE activity events
960 textual hint requests
453 code hint requests
Note: This dataset is open source, and we encourage you to take a look. It can be used for further analysis in a research project, or even just for educators to see how beginner learners are programming.
Process mining and our dataset: Preliminaries
After collecting this data, we conducted a quantitative analysis of the students’ behavior. To do this, we used a process mining technique. Process mining turns log or event data into behavioral models using action analysis, taking into account both event frequency and sequence. In business settings, the technique can help companies see where improvements are needed, as is argued for in this process mining manifesto, and save a lot of money, for example, by finding instances of duplicate payments or minimizing complex order delays.
Although it is primarily used in industry settings, process mining has already been applied in educational domains (see this paper and this paper for examples). As far as we know, we are the first to use process mining to analyze programming hint systems.
To apply this technique to our hint-systems dataset, we first extracted all hint-request sessions from the dataset (1,050 in total). The data from these sessions are the input for the analysis, which uses specialized algorithms to map the activities and transitions between them.
The sessions began when a student requested a hint. By clicking Get Hint or Retry, they ended when it was clear that the hint was processed, either by accepting the code hint or closing the text hint banner. The session was also considered “over” if the student ran into an error or there was no activity for five minutes.
We also defined different activities within sessions. Here are the activities:
Hint Button Clicked: The student clicks GetHint to generate a hint.
Hint Retry Clicked: The student clicks Retry to regenerate a hint.
Hint Code Generated: The code hint is generated. By tool design, this action is triggered every time GetHint is clicked.
Hint Banner Shown: The banner with a textual hint is shown to the student. Although this action is carried out by the system, not by the student, it marks the moment when the student has viewed the hint. This action will be used for a more detailed analysis.
ShowCodeHintClicked: The student clicks Show Code to show a code hint.
Hint Accepted: The student clicks Accept to accept a code hint.
Hint Banner Closed: The student closes the textual hint banner.
Hint Canceled: The student clicks Cancel to decline a code hint.
Error Occurred: This action includes cases where internal errors occurred during the hint generation process, e.g. problems with the internet connection, or when the LLM did not provide a response.
All sessions began with items 1 or 2, i.e. clicking Get Hint or Retry. A session could end with different activities, with the most common being items 6, 8, and 9: Hint Accepted, Hint Canceled, or Error Occurred.
In the analysis, we coded the sequence of activities within each session. We also grouped the sessions into the following three main types:
Positive Student accepted the code hint
Neutral Student saw a hint but didn’t clearly accept or reject it
Negative Student canceled a hint or got an error
The first and last types are straightforward: For the positive type, the session ended when the student accepted the code hint. For the negative, the session ended because the student did not use the hint, having received an error or actively cancelled the hint.
The neutral type will be looked at in more detail in the next section, as it required additional analysis to determine how helpful the student found the hint. We know by the actions carried out that the student saw a text or code hint, but they proceeded without explicitly accepting the code hint. Examples of neutral sessions include the following (Hint Code Generated has been omitted, as it automatically occurs as the second step in each):
Hint Retry Clicked → Hint Banner Shown
Hint Button Clicked → Hint Banner Shown → Show Code Hint Clicked
Hint Retry Clicked → Hint Banner Shown → Hint Banner Closed
The numbers below shows the distribution of session types among the 1,050 total sessions.
Positive: 299 (28%)
Neutral: 420 (40%)
Negative: 284 (27%)
The above shows that strictly positive sessions make up about a third of all sessions. As will be discussed below, we found out that the neutral cases often actually were successful in helping the students with their tasks, even if not positive as defined above. Namely, in these cases students clearly analyzed and used the content of the hints but did not automatically apply them.
Note that 266 of the 284 (94%) negative sessions ended with errors, rather than the student cancelling the hint. These errors were either internet connection issues on the student side or a system issue on our side; we have already fixed any such system errors. In addition to these three types listed above, we collected 47 data points, accounting for 4,5% of the sessions, that were not classifiable based on the available data.
With these preliminary data about the “events”, we were able to move on to applying the process mining technique for our analysis. The next subsection describes these results.
Process mining and our dataset: Analysis
We turned the data described in the previous subsection into a map of how students moved through the system. This sort of map is also called a process behavior graph. The graph for our dataset is displayed below; as it is quite complex, we will explain the most important parts individually.
In the above graph, some boxes are colored, while others are not. The blue boxes at the top represent activities that begin a session, either by generating a new hint or retrying a hint; the red boxes on the left represent activities that end a negative session; the green box at the bottom is the activity that can end a positive session; and the other activities represent activities that can otherwise happen during a session.
The arrows indicate the direction of transitions, and the numbers next to the arrows indicate the average time in seconds for each transition. Longer times, particularly those around 900 seconds, indicate that the student was solving the task and then returned for another hint. In those cases, a new event would have been triggered.
Each arrow’s transparency and thickness represent information about the frequency and average prevalence. As can be seen in the fragment below, the most frequent transitions occurred from the blue box Hint Button Clicked to white boxes Hint Code Generated and then to Hint Banner Shown.
The arrows that circle back to themselves, such as in the snippet below, represent those instances in which students repeatedly clicked the same button. In the case of the white box Show Code Hint Clicked, we think this suggests that the student might not have understood how the code hint worked, and that a future iteration of the tool would need to provide more explanation to help the student.
Looking more closely at the negative sessions, we can see in the following image two arrows coming from the red box labelled ERR. The right arrow with an 18.7-second average leads to HRC, or Hint Retry Clicked. The left arrow with > 900 s leads to HBC, or Hint Button Clicked.
These patterns indicate that even when the student encountered an error, such as a bad internet connection, they persisted in generating a new hint, either within the same task or in another. This is an important insight because it shows that students are motivated to use the hints tool even when encountering errors or negative scenarios.
In the image below, we can also see that between the blue Hint Button Clicked and various white boxes, there is an arrow going back to the blue HBC button. We interpret these transitions as indicating that the students modified their code to generate additional variations of the same hint before integrating the information into a solution. That is, the pattern suggests that they did not simply click Accept Hint, but tried to solve the task themselves.
In the classification part of the analysis described in the previous subsection, these types of activities usually comprised the sessions labelled as neutral, as they often did not end with the student accepting the hint. These and other unexpected patterns were why we wanted to hear more from these students about why they behaved the way they did.
Qualitative behavioral analysis
As described in the previous section, we observed three types of sessions when the students interacted with the AI-powered hint system. We categorized a session as positive when the student ended the trajectory by clicking Accept Hint, as the tool is working as intended. We categorized a session as negative if the student received an error message or they themselves canceled the hint. Interestingly, the students still persevered in trying for new hints despite errors.
Finally, we categorized sessions as neutral when the student clearly saw the hint but did not end the session like in positive or negative sessions. This means they saw the hint, but did not apply it to their code; for this reason, we do not consider these sessions negative or unsuccessful. Our analysis shows that neutral sessions make up 40% of all sessions, and we were curious about what exactly the students’ strategies were.
In order to learn more about what the students were thinking, we selected a subset of the participants so that they represented different experience levels, as well as locations. We conducted six semi-structured interviews, each lasting approximately 30 minutes. The interviews had two main sections: asking the participants about their experience with AI-powered hints and about any other forms of assistance they might have used while completing the tasks.
Let’s look at what is going on in the neutral scenarios. We will focus on reporting two kinds of behaviors in these neutral scenarios: selective use of hints and combining partial solutions.
Selective use of hints
From these interviews, we learned that some participants chose to work with the code hints manually instead of clicking Accept Hint. The reasons for this depended on the situation: sometimes they chose to manually alter their code for improved learning, i.e. so that they could better remember how to fix the problem next time; sometimes they only wanted to use part of the code hint. We call this behavior selective use of hints.
In the log data, we could see that the students opened the visual diff window in the code editor. This window allows the student to view both their own code and the code hint. After opening this window, the students then manually typed in the recommended code from the hint – if the hint was clear.
We can show you two examples where the hints were unclear. In the first, the text hint suggested that an image should be trimmed before applying filters, and that this trimming could be done by storing a temporary result in a variable. This can be seen in the image below, inside the box bordered by a dotted line.
As can be seen above, the student did not completely follow the hint; instead they only trimmed the image and did not create a new variable. An advantage of the in-IDE format over a course in an online editor is that the IDE will show the student an optimized way to proceed with the removed variable, even though the hint had suggested otherwise. The student’s strategy in this example suggests that students are not unquestioningly accepting hints, but are actually analyzing and adapting them for their benefit.
In a second case, the text hint suggested that the student should add a Boolean variable to store the result of a game. The image below displays the hint, as well as the various student attempts, which included a few compilation errors.
The text hint was not wrong, but it did not provide the full story: in Kotlin, Boolean variables can be initialized later when used in a loop, and so it provided the code without any initial value. Based on the student’s attempts to compile, they did not understand this language-specific feature.
From looking more closely at the students’ behavior concerning selective use of hints, we learned both that students are actively trying to adapt the hints so that they can learn better and that, in creating the hints, we should take into account language-specific features that a beginner student might not yet know about. Both takeaways form a solid basis for future investigations.
Combining partial solutions
In the qualitative analysis of the AI-powered hints tool, we additionally learned that the students sometimes combined information from multiple hint attempts, instead of using only one hint. In the log data, this appeared as clusters of closely spaced hint requests on the same portion of code, followed by students editing the solution themselves rather than just copy-and-pasting code. This behavior is depicted schematically in the image below.
This behavior, which we call combining partial solutions, can be seen as a strategy to develop a working solution by troubleshooting and making small changes to their solutions, each time generating a new hint. As with the previous behavior, students did not accept the code hint, which is why we categorized it as a neutral and not a positive scenario.
Within this analysis, we found that students often toggled between their original code version and multiple hints: they kept the previous code hint windows open. We did not expect this behavior from students using the hint tool and will investigate further in future work.
We also observed that students sometimes copied their original code outside the task environment, reusing it later alongside new attempts. In the end, they were able to obtain a working solution with this strategy. This is another behavior that we did not expect from the students, and we are interested in investigating it further in the future. More specifically, we would like to provide the participants with multiple hints simultaneously (instead of sequentially), so that they can construct a working solution efficiently and effectively.
From this analysis, we have learned that the hint tool could benefit from better support for partial adoption of hints and designs that embrace the way students naturally mix system suggestions with their own understanding and ideas, so that the student does not have to manually open multiple windows or copy-and-paste code from outside the IDE.
Furthermore, what we can understand from this behavior of combining partial solutions is that the students are active problem solvers. That is, they are not just clicking through the hints so that they can advance to the next step or lesson. Instead, students analyze the hints and adapt them to get even a better solution – critical thinking skills like these are invaluable in the LLM era.
Explore it yourself
Interested in learning programming with the help of our AI-powered hints tool? Check out our JetBrains Academy course catalog.
You can also use our data to do your own research to discover something new about how students use smart feedback in online programming courses.
Explore our dataset
And finally, if you’re interested in collaborating with our team, let us know!