Upload
agile-lietuva
View
78
Download
5
Embed Size (px)
Citation preview
This space intentionally left blank
COMPREHENSIBLE CODECOMPREHENSIBLE CODE2017, Vaidas Pilkauskas
@liucijus2017, Vaidas Pilkauskas
@liucijus
GREEN
YELLOW
BLUE
PINK
PINK YELLOWGREENBLUE
REDBLACK GREY
BROWN
COMPREHENSIBLE CODECOMPREHENSIBLE CODE2017, Vaidas Pilkauskas2017, Vaidas Pilkauskas
@liucijus
/** * User: Vaidas_pilkauskas * Date: 17/11/10 * Time: 15:12 */
…, programs must be written for people to read, and only incidentally for
machines to execute
—SICP
WHO READSTHE CODE?
WHO READSTHE CODE?
mrhayata | Flickr
YOU
THE FUTURE YOU
USERS
CONTRIBUTORS
FUTURE MAINTAINERS
READABLE CODEOptimized for reading
Cleanly editedExplicitly structured
https://wallpaperscraft.com/download/cat_window_broken_peep_104131/1920x1080
Lennart van Uffelen
COMPREHENSION
LONG LINES
HOW LONG?
Readable is less than 80, but:
→ Intellij IDEA has default marker at 120
Many tools work with 120
EXAMPLES OF VISUAL NOISE
INCONSISTENCY
UNCONVENTIONAL STYLE
TOOL WARNINGS
EXCESSIVE EMPTY LINES
UNUSED IMPORTS
UNFORMATTED CODE
IGNORING WARNINGS
IGNORING WARNINGS
Puts Broken Window into effect
IGNORING WARNINGS
False warnings hide important ones
IGNORING WARNINGS
Distractions (context switch)Inbox Zero problem
DEALING WITH WARNINGSFix the code—the best option
Disable/configure warnings to fit the code
Ask vendor to provide good defaults
ILLOGICAL CODE STRUCTURE
LOGICAL STRUCTURE
Group of elements which are in the same level of abstraction
aspects.setAspect(Web(request.url, request.remoteIp, request.remotePort, request.localIp, request.localUrl, UserAgent.from(request.userAgent), request.cookieDomain, request.appUrl, Id(request.requestId), request.dateTime, request.isRpcRequest, WebGeo(request.geo), request.getServerName))
aspects.setAspect(Web(request.url, request.remoteIp, request.remotePort, request.localIp, request.localUrl, UserAgent.from(request.userAgent), request.cookieDomain, request.appUrl, Id(request.requestId), request.dateTime, request.isRpcRequest, WebGeo(request.geo), request.getServerName))
aspects.setAspect(Web(request.url, request.remoteIp, request.remotePort, request.localIp, request.localUrl, UserAgent.from(request.userAgent), request.cookieDomain, request.appUrl, Id(request.requestId), request.dateTime, request.isRpcRequest, WebGeo(request.geo), request.getServerName))
aspects.setAspect(Web(request.url, request.remoteIp, request.getRemotePort, request.localIp, request.localUrl, UserAgent.from(request.userAgent, request.cookieDomain, request.appUrl, Id(request.requestId), request.dateTime, request.isRpcRequest, WebGeo(request.geo), request.getServerName))
aspects.setAspect(Web(request.url, request.remoteIp, request.getRemotePort, request.localIp, request.localUrl, UserAgent.from(request.userAgent, request.cookieDomain, request.appUrl, Id(request.requestId), request.dateTime, request.isRpcRequest, WebGeo(request.geo), request.getServerName))
aspects.setAspect(Web(request.url, request.remoteIp, request.remotePort, request.localIp, request.localUrl, UserAgent.from(request.userAgent), request.cookieDomain, request.appUrl, Id(request.requestId), request.dateTime, request.isRpcRequest, WebGeo(request.geo), request.getServerName))
aspects.setAspect( Web( request.url, request.remoteIp, request.remotePort, request.localIp, request.localUrl, UserAgent.from(request.userAgent), request.cookieDomain, request.appUrl, Id(request.requestId), request.dateTime, request.isRpcRequest, WebGeo(request.geo), request.getServerName ))
aspects.setAspect( Web( url = request.url, remoteIp = request.remoteIp, remotePort = request.remotePort, localIp = request.localIp, localUrl = request.localUrl, userAgent = UserAgent.from(request.userAgent), cookieDomain = request.cookieDomain, appUrl = request.appUrl, id = Id(request.requestId), timestamp = request.dateTime, isRpcRequest = request.isRpcRequest, geo = WebGeo(request.geo), serverName = request.getServerName ))
val webAspect = Web( url = request.url, remoteIp = request.remoteIp, remotePort = request.remotePort, localIp = request.localIp, localUrl = request.localUrl, userAgent = UserAgent.from(request.userAgent), cookieDomain = request.cookieDomain, appUrl = request.appUrl, id = Id(request.requestId), timestamp = request.dateTime, isRpcRequest = request.isRpcRequest, geo = WebGeo(request.geo), serverName = request.getServerName)
aspects.setAspect(webAspect)
val client = Client( name = ..., addresses = Seq( Address( type = Work, building = Building( room = Room(301), street = Street(“Rūdninkų”), city = City(“Vilnius”), zip = Zip(“123123”), ) ) ))
ARGH! BRACES!!1
{ “foo”: “bar”}
<foo> <bar /></foo>
Foo( “bar”)
{ “foo”: “bar”}
<foo> <bar /></foo>
Foo( “bar”)
Tools and Formatting
val message = ContactActivityMessage(builder.tenantDetails.metaSiteId.getId.asGuid, constructNotifyActivityInfoDto(userActivity), constructNotifyContactInfoDto(contact))
val message = ContactActivity(builder.tenantDetails.metaSiteId.getId.asGuid, constructNotifyActivityInfoDto(userActivity), constructNotifyContactInfoDto(contact))
val message = ContactActivity( builder.tenantDetails.metaSiteId.getId.asGuid, constructNotifyActivityInfoDto(userActivity), constructNotifyContactInfoDto(contact))
val message = ContactActivityMessage( builder.tenantDetails.metaSiteId.getId.asGuid, constructNotifyActivityInfoDto(userActivity), constructNotifyContactInfoDto(contact))
Examples
val asSiteContact = contact.details.asSiteContact(count) .copy(lastActivity = updated)
// BAD: Chain logic group split
val asSiteContact = contact.details.asSiteContact(count).copy(lastActivity = updated)
// GOOD: Chaining on the same line
val asSiteContact = contact .details .asSiteContact(count) .copy(lastActivity = updated)
// GOOD: Chain member per line
enum State { READ, WRITE, PAUSE, STOP}
// BAD: Broken logical group
enum State { READ, WRITE, PAUSE, STOP}
// WORSE: Looks clean, but has broken logical group
enum State { READ, WRITE, PAUSE, STOP}
enum State { READ, WRITE, PAUSE, STOP}
// GOOD
val foo = Foo(Bar(baz = Varoom( prop1 = "val", prop2 = "val2", prop3 = "val3), faz = Seq("one", "two")))
operations.query(contactById, Map( "site_id" -> getBytes(siteId), "contact_id" -> getBytes(contactId)), ContactMapper)
// BAD: hard to spot relations
val foo = Foo( Bar( baz = Varoom(prop1 = "val", prop2 = "val2", prop3 = "val3), faz = Seq("one", "two") ))
operations.query( contactById, Map( "site_id" -> getBytes(siteId), "contact_id" -> getBytes(contactId) ), ContactMapper)
// GOOD: explicit relations
case class Activity(contact: Contact, created: Instant, payload: String)
// BAD: fields in the same logical group given uneven placement
case class Activity(contact: Contact, created: Instant, payload: String)
case class Activity( contact: Contact, created: Instant, payload: String)
case class Activity( contact: Contact, created: Instant, payload: String)
// GOOD: all fields are equally significant
CAN STRUCTURE BE AUTOMATED?
Concentrate on communicating intent,but Automate repetitive work
There are other ways to communicate
CODE COMPREHENSIONis based on
NAMED ABSTRACTIONS and CODE STRUCTURE
THANK YOU!
QUESTIONS?