Skip to content
This repository has been archived by the owner on May 9, 2019. It is now read-only.

Transaction Service - Submit delivery details #94

Merged
merged 21 commits into from Jun 21, 2017
Merged

Conversation

yg-apaza
Copy link
Contributor

@yg-apaza yg-apaza commented Jun 1, 2017

Use Case 3: As a buyer, I want to submit delivery details for the seller

  • Update TransactionEntity, command: SubmitDeliveryDetails, event: DeliveryDetailsSubmitted and state
  • Add tests: shouldForbidSubmittingDeliveryDetailsByNonBuyer, shouldEmitEventWhenSubmittingDeliveryDetails
  • UI and Controllers on web-gateway
  • Add getTransaction and fill form of DeliveryDetails in UI
  • Show transaction details
  • Add integration tests (shouldCreateTransactionOnAuctionFinished, shouldNotCreateTransactionWithNoWinner, shouldSubmitDeliveryDetails)

@yg-apaza
Copy link
Contributor Author

yg-apaza commented Jun 2, 2017

@jroper @TimMoore

@yg-apaza yg-apaza changed the title [WIP] Transaction Service - Submit delivery details Transaction Service - Submit delivery details Jun 6, 2017
@yg-apaza yg-apaza changed the title Transaction Service - Submit delivery details [WIP] Transaction Service - Submit delivery details Jun 7, 2017
@yg-apaza yg-apaza changed the title [WIP] Transaction Service - Submit delivery details Transaction Service - Submit delivery details Jun 12, 2017
@yg-apaza
Copy link
Contributor Author

This PR is now finished 😅
@jroper @TimMoore @ignasi35 , could you please review?

@ignasi35
Copy link
Contributor

On it...

import lombok.Value;

@Value
public class DeliveryData {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is the private representation of the transaction-api's DeliveryInfo.

We have a terrible mix of naming convetions in that sometimes the private copy is PXyz, sometimes it's the exact same name with only a package difference, ...
In general I hate using Data and Info for anything other than signifying that data is master and info can be derived from data.

I don't think this issue of naming should be solved in this PR but it' be good if we settled and considered creating a convention.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Raised #98

);
}
else
throw new Forbidden("Only the auction winner can submit delivery details");
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you'd better use ctx.failed here. Throwing an exception will kill the underlying actor and cause it to be rebuilt. If you use ctx.failed you are signaling the command process completed successfully with a rejection.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changing this will break your tests.
Also, I've just noticed there's a similar case few lines below this.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if that's the case - I think all commands are processed in a try catch, and when a command handler throws an exception, Lagom catches it and passes it to ctx.failed for you.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, can I throw an exception? Using ctx.failed breaks test, is it related with lagom/lagom#325?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While browsing the Lagom source code, found this
As @jroper said, commands are inside a try catch, so I think it's safe throwing an exception
I changed this in the latest commit

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think ctx.failed would be a better example of what we consider best practices... I'm not sure why it's failing the test, but we can look at it in a separate pull request. This is OK for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since some services use throw new(...) and others ctx.commandFailed, I raised #108

}
else
return Optional.empty();
}
Copy link
Contributor

@ignasi35 ignasi35 Jun 12, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very common antipattern of Optional. A if(opt.isPresent) {...} else {Optional.empty} is equivalent to Optional.map(). The code can be rewritten as:

        return data.map(deliveryData -> new DeliveryInfo(
                deliveryData.getAddressLine1(),
                deliveryData.getAddressLine2(),
                deliveryData.getCity(),
                deliveryData.getState(),
                deliveryData.getPostalCode(),
                deliveryData.getCountry()
        ));

NOTE: IntelliJ made the suggestion and the rewrite for me. IntelliJ detected the antipattern and marked the code in brown, then using Alt-return made the fix.

);
}

public static TransactionInfo toApi(TransactionState data) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is dead code. Is that correct? Is that WIP?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I forgot to delete it 😅

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevermind, I'm using TransactionInfo toApi(TransactionState data)here

}

public static TransactionInfo toApi(TransactionState data) {
Transaction transaction = data.getTransaction().get();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

get() could throw a NullPointerException.
Should this code consider the case where data.getTransaction() returns empty? If that can't happen, then It'd be great to have a comment: // this code is always executed when transactions is set so we can get() safely.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a comment, using get() is safe

@ignasi35
Copy link
Contributor

This is great work and you are progressing steadily!
I haven't reviewed the UI/Play portion but it looks awesome.

@ignasi35
Copy link
Contributor

I was looking for some examples in other services and found 2 TODOs: Use Forbidden instance and Avoid using TransportException. Aren't these contradictory?

They are.

So far the approach we're using is: if the service is mall enough then use some transport exceptions inside the Persistent Entity. If you think using more domain-rich exceptions will make the code more maintainable then don't.

@ignasi35
Copy link
Contributor

Hi @yg-apaza earlier I forgot to mention that this PR doesn't have any integration test (start a server, send some requests and/or messages via a topic stub). Is that on purpose?
Would it be benefitial to add a couple of happy-path tests as we move forward with this service ?

@ignasi35 ignasi35 added the enhancement New feature or request label Jun 12, 2017
@ignasi35 ignasi35 requested a review from TimMoore June 12, 2017 14:07
@yg-apaza
Copy link
Contributor Author

How about now? @ignasi35 @TimMoore @jroper

TransactionInfo retrievedTransaction = transactionService.getTransaction(itemId)
.handleRequestHeader(authenticate(creatorId))
.invoke()
.toCompletableFuture()
.get(5, SECONDS);

assertEquals(retrievedTransaction, transactionInfoWithDelivery);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure this test is correct.
I mean, the test does pass, but it uses eventually in a way that's not safe and which we shouldn't promote:

  • eventually is a loop that is executing a block of code with an assertion that eventually becomes successful. The key thing is that the code block is run over and over, which means the code in transactionService.submitDeliveryDetails... is invoked several times. IIUC, that code is not idempotent in the TransactionServiceImpl + TransactionEntity classes.

@ignasi35
Copy link
Contributor

Other than my previous comment it LGTM


eventually(new FiniteDuration(15, SECONDS), () -> {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Copy link
Contributor

@TimMoore TimMoore left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice work!

I had a couple of comments, but I'm going to go ahead and merge this. Please consider those changes in another pull request. In general, it would be better to keep pull requests small and focused. This one is large enough that it's hard to review it carefully without getting lost 😄

);
}
else {
String msg = ((TransportException) exception.getCause()).exceptionMessage().detail();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure that it's safe to always assume that exception.getCause() will always be a TransportException.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm going to fix this as part of #107

@TimMoore TimMoore merged commit fb7e30c into lagom:master Jun 21, 2017
@yg-apaza yg-apaza deleted the UC03 branch June 22, 2017 03:44
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement New feature or request
Development

Successfully merging this pull request may close these issues.

None yet

4 participants