Dom Finn, Lead Developer at UNiDAYS
@cleverfinn
Robust
/roh-buhst/ - adjective
Strong and effective in all or most situations and conditions
Robust
/roh-buhst/ - adjective
Strong and effective in all or most situations and conditions
Robust
/roh-buhst/ - adjective
Strong and effective in all or most situations and conditions
Robust
/roh-buhst/ - adjective
Strong and effective in all or most situations and conditions
try
{ businessCriticalThing1(); businessCriticalThing2(); } catch (BadDevelopmentPractice b) { b.sweepUnder(rug); }
Who Cares?
Accounts - Code Management
Ops - Code Management
Support - On-Site Known Issues
Support - Support Team
Support - Social Team
Legal - SLAs
Commercial Analytics - Data loss
Business - KPI Impact
Everything (else)
CAP
Side Effect 1
Side Effect 2
Side Effect 3
Action
(Combinatorics)
public ActionResult UpdateUser(UserViewModel viewModel)
{
var user = userRepository.Get(viewModel.Id);
user.Email = viewModel.email;
user.Password = viewModel.password;
emailService.SendAccountUpdatedEmail(user);
userRepository.Update(user);
reportService.RecordEvent(new UserUpdatedEvent(user));
return Redirect("/user-updated");
}
1) Email | 2) Update | 3) Report | |
---|---|---|---|
Pass | Pass | Pass | Yes |
Pass | Pass | Fail | Yes |
Pass | Fail | No | |
Fail | No |
1) Update | 2) Report | 3) Email | |
---|---|---|---|
Pass | Pass | Pass | Yes |
Pass | Pass | Fail | Yes |
Pass | Fail | Yes | |
Fail | No |
1) Email | 2) Report | 3) Update | |
---|---|---|---|
Pass | Pass | Pass | Yes |
Pass | Pass | Fail | No |
Pass | Fail | No | |
Fail | No |
1) Update | 2) Email | 3) Report | |
---|---|---|---|
Pass | Pass | Pass | Yes |
Pass | Pass | Fail | Yes |
Pass | Fail | Yes | |
Fail | No |
25%
50%
75%
75%
1) Report | 2) Email | 3) Update | |
---|---|---|---|
Pass | Pass | Pass | Yes |
Pass | Pass | Fail | No |
Pass | Fail | No | |
Fail | No |
25%
1) Report | 2) Update | 3) Email | |
---|---|---|---|
Pass | Pass | Pass | Yes |
Pass | Pass | Fail | Yes |
Pass | Fail | No | |
Fail | No |
50%
public ActionResult UpdateUser(UserViewModel viewModel)
{
var user = userRepository.Get(viewModel.Id);
user.Email = viewModel.email;
user.Password = viewModel.password;
+ userRepository.Update(user);
emailService.SendAccountUpdatedEmail(user);
- userRepository.Update(user);
reportService.RecordEvent(new UserUpdatedEvent(user));
return Redirect("/user-updated");
}
Requires:
Side Effect 1
Side Effect 2
Side Effect 3
Action
Action
Side Effect 1
Side Effect 2
Side Effect 3
(Immediately Consistent Path)
public ActionResult UpdateUser(UserViewModel viewModel)
{
var user = userRepository.Get(viewModel.Id);
user.Email = viewModel.email;
user.Password = viewModel.password;
userRepository.Update(user); emailService.SendAccountUpdatedEmail(user); reportService.RecordEvent(new UserUpdatedEvent(user)); return Redirect("/user-updated"); }
try { var user = userRepository.Get(resource.Id); try { userRepository.Update(user); try { emailService.SendAccountCreatedEmail(user); } catch { } try { reportService.RecordEvent(new UserUpdatedEvent(user)); } catch { } } catch { } } catch { }
*mostly
try { // do stuff } catch { // just in case lolol }
1) Bury your head
try { // do stuff } catch (Exception e) { // no idea what will be thrown }
2) Catch all the things
try { // do stuff } catch { throw; }
3) Hot potato
Theres a time and a place...
(Probably not when and where you’re using them)
Cue sweeping generalisations...
Guid ConvertToGuid(string guid)
{
return Guid.Parse(guid);
}
No
Guid ConvertToGuid(string guid)
{
try
{
return Guid.Parse(guid);
}
catch
{
return Guid.Empty;
}
}
No
Guid ConvertToGuid(string guid) { Guid g; if(Guid.TryParse(guid, out g); return g; return Guid.Empty; }
Yes
try { var user = userRepository.Get(resource.Id); try { userRepository.Update(user); try { emailService.SendAccountCreatedEmail(user); } catch { } try { reportService.RecordEvent(new UserUpdatedEvent(user)); } catch { } } catch { } } catch { }
public enum ExecutionResult { Success = 1, Failure = 2 } public sealed class ExecutionResult<T> { public T Data; public ExecutionResult Result; }
User IUserRepository.Get (Guid id); void IUserRepository.Update (User user); void IEmailService.SendWelcomeEmail (User user); void IReportService.RecordEvent<TEvent> (TEvent @event);
ExecutionResult<User> IUserRepository.Get (Guid id); ExecutionResult IUserRepository.Update (User user); ExecutionResult IEmailService.SendWelcomeEmail (User user); ExecutionResult IReportService.RecordEvent<TEvent> (TEvent @event);
Before
After
var userResult = userRepository.Get(resource.Id); if(userResult.Result == ExecutionResult.Failure) return ErrorResult.ServiceUnavailable(); var user = userResult.Data; var result = userRepository.Update(user); if(userResult.Result == ExecutionResult.Failure) return ErrorResult.ServiceUnavailable(); emailService.SendAccountUpdatedEmail(user); // ignore result status reportService.RecordEvent(new UserUpdatedEvent(user)); // ignore result status
var thing = getThing(thingId); // just in case, lol! if(thing == null) return; thing.doThing();
var thing = getThing(thingId); var things = getThings();