Over the last couple of weeks, I ran into one of my first major hurdles in understanding how to use a set of features that I love to use within the .NET space: Entity Framework Core as an ORM (Object Relational Mapping). As an experienced software engineer in .NET, I prefer to use an ORM such as Entity Framework over doing straight SQL within code to connect to databases. There are several advantages, such as the flexibility to use different databases with minimal code changes. Also, many ORMs optimize the SQL generated with the database provider, so I can be less concerned about writing this great SQL, and let the ORM do the task that it is good at.
What happened?
While working on the Planning Poker API, I was starting out by building out the basic Models and Repositories that would fetch the data from the database. In this effort, I wanted to avoid using straight SQL in my code, so I researched what solutions exist within Java Spring to fill this need. In doing my research, I ran across Spring Data JPA. Spring Data JPA is a feature you can leverage within the Spring framework to define models and repositories using Annotations, and then define the relationships on top of that. I dove into this and leveraged Co-pilot along the way to build out my models using JPA based on descriptions of the entities and adjusted some of the small details along the way.
I did eventually hit a stumbling block in which I didn’t understand what the source of the problem was. I got an error when trying to run the Spring Application tests, and got an error saying a dependency couldn’t be mapped. I kept struggling with this problem and didn’t understand the root cause of this exception and fought with Copilot and even used the Gradle build scans to understand and find resources to help explain the problem. I was getting nowhere and was getting frustrated. After taking some time away and coming back I did finally figure out the problem.
In .NET, I know how to navigate and read the exception path, and in .NET I’ve gotten experience on how to hunt down the exception tree to find the root/base exception. In Java, this is done slightly differently, the output of the exception will trace down using the keyword “caused by” and have a new subset of Java stack trace statements. I haven’t touched Java in a while, and wasn’t used to this new formatting for me and once I finally searched what the base error was, I was able to track down the issue was an ambiguous reference in a mapping, caused by not adding the correct relationship annotation on the navigation property. After I corrected this, suddenly all the tests passed.
Learnings From This Experience
There were a few learnings from this experience. The first, and honestly biggest learning for me, was how to read the console output and build logs more effectively. They contain a lot of relevant information, but I now know how they are formatted so that I can more effectively research and troubleshoot problems.
Another useful learning of this, was when I was talking to a colleague and I was talking about IDEs available for personal use, I mentioned how I like using IntelliJ at work (Enterprise), but I was using VisualStudio Code at home since I wasn’t going to buy the Enterprise version of IntelliJ. He mentioned there is a community edition for personal side use, which this is a perfect case for. Since installing IntelliJ Community Edition, I have had a better experience getting the debugger to work in a way that I can use it.
The last learning, which is hard to adjust to, is that when I am using AI assistance, like Co-pilot, the query will look very different from what I am used to for searching Google. AI prompts allow for more details and do try to sift through the prompt more efficiently than a Google search would. There is an anti-pattern though because something to also keep in mind, if you are using an updated framework, if the framework is less than 6 months old, it might not be fully included int he LLM and thus you may not get the best answer for your given situation, so knowing when to search for additional documentation and info is useful.
Conclusion
When re-learning or translating skills between languages, understanding some of the core principles is very useful. The things to think about are syntax, build type, build commands, and basic logging. If you can understand how a framework or language builds, then you can trace and track issues more effectively. If you understand how logging works and the order and details, then that will expedite troubleshooting.