Your Web News in One Place

Help Webnuz

Referal links:

Sign up for GreenGeeks web hosting
December 23, 2021 11:20 am GMT

End to end Debug Object Modeling. First hard problem in Building DDTJ - Day 4

Yesterday I got the second PR out of the door (and the 3rd although that was automated). Today wasn't as productive...

Winter just started in full force around these parts, and yesterday, everything was flooded. This slowed down some of my work, especially after my son's kindergarten was flooded and he had to stay home. Still, I could make progress thanks to the fact that the code now runs end to end. That means I can start debugging the whole thing by using the command line and setting a breakpoint in the backend. Very convenient.

I can now finally start collecting data. I've also run into my first hard problem that Ive been avoiding mentally for a while

The Problem

Debugging the app is mostly trivial. Lets say we invoke a method and get an event. Specifically, a MethodEntryEvent. In that event, we can grab the values of the arguments, etc. This is also the case later on when we invoke the APIs we need to mock. But thats for later Right now, lets focus on that.

The debugger returns a somewhat problematic value type. Well need to pull all of that data locally (the debugger is a remote VM) to debug that. The core problem is with a deep object graph. E.g. lets say I have a method such as:

void method(Root obj) {    //...}

Now Root contains a reference to every object in the system. If we want to invoke this method correctly in a future execution, do we need to pull Root and all its data?
Thats insane. There has to be a better way...

But thats the smaller problem. Lets say we have an object's data locally. How do we physically create an instance with the right values to pass to a method?
Do we use a constructor? A builder? Or is it all 100% mocked?

If its the latter, will the code be readable?

Will the test we generate pass?

I had given this a lot more thought in the past day, and Im a bit conflicted here. An approach I sometimes take in these cases is to see these things all the way through, then refine the result to something I like. Sometimes the solutions reveal themselves as we get closer.

Here are a few ideas I had to solve the problem...

The Insane Idea

One idea I had is:

  • Watch every object creation and log that
  • If a new type of object is created or its created in a new way, we can connect the creation process to the fields
  • If the constructor is public, we can use that
  • If its a builder, we can follow the process from there

As I write this, the idea seems even crazier than it sounds in my head, but it might be doable. At least partially.

Not as Insane Idea - Heuristics

The insane idea is indeed a bit too much. But there are things we can do to reach a similar effect for most common code.

Id say 98% of objects fall into pretty common patterns for creation and conventions. By just programming the most common heuristics, we can probably auto-generate 98% of the tests correctly and the last 2% well Thats probably a tiny fix to make.

  • If a class has a setter matching the field name Great problem solved
  • If the class doesnt have a default constructor, but has a constructor that accepts parameters matching the fields. Pass the fields based on argument name or type if the name doesnt match
  • If neither of those match check for a static method that returns the class instance
  • Finally, look for builder calls

If I choose to take this route, Ill probably implement the first two for the MVP.

The Hack

Another approach is to skip this altogether and serialize the object. We can allocate and inject the fields. Unfortunately, I doubt the code would look great. I think thats the main reason the ideas above are so appealing.

However, for pure data objects, this might not be a terrible idea.

The Obvious Idea (Mocking)

Obviously, mocking all objects that are passed in has its value. But Im not sure if thats what we would really like to do. Mocking code is pretty verbose. It also doesnt increase the coverage of the mocked class.

Even if we go with the mocked approach, this still wouldnt be trivial and can end up nesting a lot since the mocked object might need to return another (mocked) object and so forth. The nesting can become quite difficult.

What Im Doing Right Now

Im still at the early stage of collecting data, so Im just collecting value object data into a simplified object. Essentially, a type of string and an object. If it's a primitive value, then its simple. I just store the value.
Initially, I tried to simplify the approach for an object. I thought that if its an object, I can create a Map with the fields of the object that arent transient. Id have a nesting constant and a recursion blocker that would stop me from going too deep into an object hierarchy. This would have allowed me to detect a link to the same object and use the same reference internally to avoid a problem. That last part I might still need. I also have a plan to block recursion so it wont go deeper than 3 levels by default.

But I dont think thats a workable solution. Well run into problems when we try to generate code based on that. I think we need to implement the not as insane idea and I think thats a workable approach. To get this working, I need an additional data point. I need to cache the class objects that we can create and those that cant. If we can create a class, we will mark it. Assuming theres a process to create the class, well know the fields that need saving.

If we cant create a class, we might still have the option of generating a mock for that class, so a test might still be possible.

As Im writing this, Im also coding the logic which will be extensive. Tomorrow it might turn out that I implemented something completely different...

Increasing Coverage

I merged the PR I worked on yesterday with decent coverage. Turns out I was missing the lombok.config file. It isnt essential, but you need to add the entry:

lombok.addLombokGeneratedAnnotation=true

Otherwise, code generated by Lombok isnt marked as generated code and is included in the coverage statistics. I had 30% coverage with 11 lines uncovered... Adding this changed the dynamic to 83%.

Today

One thing that sucked at the end of day yesterday Turns out I copy pasted a typo in the document title for the last couple of days and it said DDJT instead of DDTJ. Ugh. I cant fix it. Its in the URLs, its syndicated etc. Spell checkers should really check the titles, but to be fair, they dont even check the acronyms at all.

Hopefully, today will be better. I plan to pull out the object state and fields as we step over the code. I was hoping for something running by the end of the week, but that will probably only happen next week.

If you find this interesting/useful it would be great if you follow me on twitter...


Original Link: https://dev.to/codenameone/end-to-end-debug-object-modeling-first-hard-problem-in-building-ddtj-day-4-179h

Share this article:    Share on Facebook
View Full Article

Dev To

An online community for sharing and discovering great ideas, having debates, and making friends

More About this Source Visit Dev To