Conversation
…NOT an error by default, e.g. with UDP)
|
@DarkStarDS9 Thank you so much for your interest in the project and your valuable contribution! Also thanks for merging v2 branch, this makes it easier to check. I will do a code review and let you know what I think. Generally I'm aware of issues like lack of handling invoke-id per remote device but this code needs to be changed step by step. I would like first of all to decouple the classes, remove all duplications and other code smells so that we have a friendly codebase to start with. Do you think your change should be merged into both, v2 and master or can we just focus on v2? |
|
That depends... 😉 My situation is as follows: I took over a two year old project where a colleague used this stack, put it into an internal repo and made some changes (including vendor-specific ones) - with no plan to push anything anywhere. I only discovered the v2 branch today, and it's probably fine for me to continue on v2. In fact, I'd very much like to see this project getting more C#-ish [encode_application_date() -> EncodeApplicationDate(), derived classes instead of unused fields (hello BacnetEventNotificationData), less boxing ((string)((List)properties[(uint)BacnetPropertyIds.PROP_DESCRIPTION])[0].Value ... what?) etc.] - and I take it v2 is the place to go for this 😉 |
|
First of all, I couldn't agree with you more about making this code more C#-ish ❤️ My story with this repo started when I discovered YABE and wanted to use it's core for a project I was assigned to at work. Like your colleague I could have just copied it into our internal repo and forget about it, but my company was ok with continuing sharing the codebase with community. First thing I did was contacting the maintainer of YABE about cooperation. I suggested him that he could use the NuGet I've created and focus only on developing the application in his repo, while maintaining the core together here. What I got in response was a rude accusation that what I'm doing is illegal, that my changes don't bring anything new (having duplications, spaghetti code and everything stored in basicaly two files is not a problem apparently) and that I should delete it. We had a laugh at the company but it's sad when you realize someone actually thinks like that... But anyway, with v2 I wanted to finally start to refactor the code, but didn't decide how drastic should it be. The code originates from some C stack (hence the coding style) but do we want to make a revolution or an evolution? Yesterday I got the same question from another member of the community (@iqbal-hassan ) about being able to provide vendor specific serialization/deserialization. Maybe we could open an issue about this and share ideas about this? As for your PR, you are right. Lets merge to both as the job is already done, and then let's focus on making the codebase great again using v2 branch 😉 |
|
YABE: that's sad. BACnet is pretty... bulky 😉 and only relevant to "a hand full" of developers, so it would make sense to work together. vendor specifics: sure, let's open an issue! evolution vs revolution: well, you did branch into v2, so you're aiming for a revolution, no? We can still do both if we commit & merge often and take care not to break any functionality. Another thing to think about: Code-Style. I'm a ReSharper-User, and there should be a way to store style-settings within the project - so if you happen to use ReSharper too, I'd suggest to add the settings to the repo. If you use something else, I guess I'll adapt 😉 |
|
Yes, v2 was created because I wanted to try to make this code look like it was written in C# from the beginning, but there are several reasons why I hesitated:
I'm a ReSharper user as well 👍 so I'm open to pushing DotSettings to the repo. I was also hoping on setting up CI for this project to check PR and deploy nugets, but so far I only set up a build on company TeamCity to compile and push new nuget from master whenever it makes sense. Hope in the future this can be more professional. |
BACnetClient.cs
Outdated
| /// </summary> | ||
| private Dictionary<byte, List<Tuple<byte, byte[]>>> segmentsPerInvokeId = new Dictionary<byte, List<Tuple<byte, byte[]>>>(); | ||
| private Dictionary<byte, object> locksPerInvokeId = new Dictionary<byte, object>(); | ||
| private Dictionary<byte, byte> expectedSegmentsPerInvokeId = new Dictionary<byte, byte>(); |
There was a problem hiding this comment.
please move the declaration of fields to the top of the class definition. Also, for private fields use underscore prefix notation to match the coding style.
There was a problem hiding this comment.
yeah... about underscore prefix: I don't like it - I find that it "breaks the flow" when reading code - and it looks so 1970.
.NET Framework Design Guidelines state "DO NOT use underscores, hyphens, or any other nonalphanumeric characters".
And yes, I am painfully aware that in .NET Core, there are underscores all over the place - that's what you get when you take it to "the community" I guess.
Why would you use an underscore to indicate private fields, but not use i_ThisIsAnInt or m_ThisIsAMember? Just tell ReSharper to give private members a different color then local variables and be done with it 😉
There was a problem hiding this comment.
I didn't like underscore too because in the past after brief rendezvous with Pascal and Delphi I was raised with C# and underscore was not present in the convention. But I also didn't like to write this. everywhere when the method argument is named the same. What is a deal breaker for now is that it's the convention here already so please adapt, later when a refactor is made on everything, this can be changed. More than personal preference (mine or yours) I value consistency.
BACnetClient.cs
Outdated
| APDU.EncodeComplexAck(encodedBuffer, type, service, invokeId); | ||
|
|
||
| _segments.AddLast(copy); // doesn't include BVLC or NPDU | ||
| mySegments.Add(new Tuple<byte, byte[]>(sequenceNumber, copy)); // doesn't include BVLC or NPDU |
There was a problem hiding this comment.
Use Tuple.Create(). In th future I would like to use value tuples. And mySegments I would change to just segments?
BACnetClient.cs
Outdated
|
|
||
| //process when finished | ||
| if (moreFollows) | ||
| if (mySegments.Count < expectedSegmentsPerInvokeId[invokeId]) |
There was a problem hiding this comment.
declare this at the beginnig of the method body to cause less changes
var moreFollows = mySegments.Count < expectedSegmentsPerInvokeId[invokeId]
BACnetClient.cs
Outdated
| r.Result, 0, r.Result.Length, out var values); | ||
| var byteCount = | ||
| Services.DecodeReadPropertyMultipleAcknowledge(r.Addr, r.Result, 0, r.Result.Length, | ||
| out var values); |
There was a problem hiding this comment.
please break line like this
var byteCount = Services.DecodeReadPropertyMultipleAcknowledge(
r.Addr, r.Result, 0, r.Result.Length, out var values);There was a problem hiding this comment.
This is Visual Studio or ReSharper breaking the line for me, I usually don't do this myself. What's your setting there?
There was a problem hiding this comment.
To be honest I always correct it myself if I get such effect 🙈 I don't know if this is possible to set to achieve this effect automaticaly. You see this version as more readable or not?
There was a problem hiding this comment.
I dislike both and would prefer to scroll 😉
Now that I took a look at the available ReSharper-Settings, I'd prefer "Chop if long or multiline" with "prefer wrap after (", which looks like this:
CallMethod(
arg1,
arg2,
arg3,
arg4,
arg5);
but really... any setting is fine, as long as ReSharper takes care of it.
There was a problem hiding this comment.
Good thing this repo doesn't have dozens of contributors as I can already see an ideaology discussion here 😆 Since we have way bigger problems in this codebase than style, how about this. For now please stick to my suggestions regarding code style, and I promise in the future to have ReSharper styles files in the repo and stick to it's automatic formatting? Maybe in time more people will join and we can use democracy to decide (or we have a big argument and everyone forks the repo 😝)
BacnetAsyncResult.cs
Outdated
| public bool CompletedSynchronously { get; private set; } | ||
| public WaitHandle AsyncWaitHandle => _waitHandle; | ||
| public bool IsCompleted => _waitHandle.WaitOne(0); | ||
| public BacnetAddress Addr { get; } |
Serialize/ASN1.cs
Outdated
| EncodeApplicationDestination(buffer, adr); | ||
| break; | ||
| default: | ||
| throw new ArgumentException(); |
There was a problem hiding this comment.
please provide argument exception message
Serialize/ASN1.cs
Outdated
| } | ||
|
|
||
| public static int decode_read_access_result(byte[] buffer, int offset, int apdu_len, out BacnetReadAccessResult value) | ||
| public static int decode_read_access_result(BacnetAddress addr, byte[] buffer, int offset, int apdu_len, out BacnetReadAccessResult value) |
| /// The address of the remote device is provided so that you can support devices from multiple vendors | ||
| /// (the same custom property# has different meaning for each vendor) | ||
| /// </summary> | ||
| public static Func<BacnetAddress, BacnetPropertyIds, byte, BacnetApplicationTags> CustomTagResolver; |
There was a problem hiding this comment.
in the future things like this will be injected (so no statics) but for now it's ok (methods are static anyway)
There was a problem hiding this comment.
yeah... about injection: I really hope you mean a constructor parameter, and not some nifty DI Framework?
There was a problem hiding this comment.
I don't want to add any dependency to DI frameworks, but the code has to be DI friendly. This means stuff has to be set using constructor parameters, properties, interfaces etc.
| catch | ||
| { | ||
| return; | ||
| } |
There was a problem hiding this comment.
remove this catch, the exception will be handled by the outer one
| SharedPort = port; | ||
| SharedPort = sharedPort; | ||
| this.exclusivePort = exclusivePort; | ||
|
|
There was a problem hiding this comment.
I know this part of code sucks. Having a property SharedPort but being used as exclusive port 😩 But anyway, before we rewrite this, I suggest as minimal changes as necessery. How about you add extra ctor:
public int ExclusivePort { get; }
public BacnetIpUdpProtocolTransport(int sharedPort, int exclusivePort, bool dontFragment = false,
int maxPayload = 1472, string localEndpointIp = "")
: this(sharedPort, true, dontFragment, maxPayload, localEndpointIp)
{
ExclusivePort = exclusivePort;
}This reverts commit a1be941.
|
This should cover everything you addressed. |
Serialize/Services.cs
Outdated
| } | ||
|
|
||
| public static int DecodeReadPropertyAcknowledge(byte[] buffer, int offset, int apduLen, out BacnetObjectId objectId, out BacnetPropertyReference property, out IList<BacnetValue> valueList) | ||
| public static int DecodeReadPropertyAcknowledge(BacnetAddress addr, byte[] buffer, int offset, int apduLen, out BacnetObjectId objectId, out BacnetPropertyReference property, out IList<BacnetValue> valueList) |
There was a problem hiding this comment.
@DarkStarDS9 just this one left, don't use addr anywhere, please use full address
gralin
left a comment
There was a problem hiding this comment.
Yup nearly done. You just missed a few places where you still have new Tuple() instead of Tuple.Create() or addr instead of address.
BACnetClient.cs
Outdated
| APDU.EncodeComplexAck(encodedBuffer, type, service, invokeId); | ||
|
|
||
| _segments.AddLast(copy); // doesn't include BVLC or NPDU | ||
| segments.Add(new Tuple<byte, byte[]>(sequenceNumber, copy)); // doesn't include BVLC or NPDU |
|
You should have write permissions on the branch you receive a pull-request from and could do those changes yourself - if there is consensus about what should be done, that usually speeds up pull-requests 😉 |
|
Sure it's just that I left my laptop at home for the weekend and it would have been difficult to do it on my smartphone 😅 |
No description provided.