How to Be a Great Technical Lead


How to choose tech stack
- List your current/near-future features
- Consider multiple/different options and how to use them to implement features 
- Compare their pros and cons: manageability, scalability 
- What techs are used in your team and departments
    - But this doesn't mean always use same tech stacks used before 
- What tech are supported by operation team

Build reputation
- be useful and help others

Know your team members
- their strength or weakness
  - programming skills
  - design skills
  - trouble shooting skills
- what they are interested, what are not
- what they want to learn and improve
Help them to grow and improve their skills

Know yourself
Know how/what you can help the team
- your programming/design/communication skills
Know when to stand alone and when to step in
Know when to let others shine

Delegation
- don't try to do everything
- let other people do the job they are good at and observe
- let others contribute and take ownership/leadership

Spring Tips & Tricks


Spring-boot
Spring-boot specifies and manages its dependencies' version:
check https://github.com/spring-projects/spring-boot/blob/master/spring-boot-dependencies/pom.xml. 
Don't specify and overwrite the version again in our project's pom.xml.
Don't use same property value to overwrite the version by accident.

Properties
@Bean public static PropertySourcesPlaceholderConfigurer propertyConfig(){}

Bind properties to a list or a map
First create ConversionService bean
@Bean public ConversionService conversionService() {
    return new DefaultConversionService();
}

my.list.of.ints=1,2,3
@Value("${my.list.of.ints}")
private List<Integer> myList

redis.expires={typeA:900, typeB: 86400}
@Value("#{${redis.expires}}")

private Map<String, Long> expires;

Spring Cache
Support Spring Expression Language in Spring AOP
In contrast to the @Cacheable annotation, @CachePut does not cause the advised method to be skipped. Rather, it always causes the method to be invoked and its result to be stored in the associated cache. 
We can use #result as key in @CachePut.

CacheAspectSupport.execute
CacheAspectSupport.generateKey
SpringCacheAnnotationParser.parseCacheAnnotations
CacheOperationExpressionEvaluator.createEvaluationContext
if (result != NO_RESULT) evaluationContext.setVariable(RESULT_VARIABLE, result);

- To support #result, we just put method return result value into the variable: result.

Synchronized caching
@Cacheable(sync="true")
@CacheConfig(cacheNames = "cacheA")
@Cacheable(key= ("#p0['name']")) // p0 is a map
@CachePut(key = "#p0.name") // p0 is an instance
@Cacheable(key = "'somePrefix-'+#p0")

public static final String PREFIX = "'" + CACHE_NAME + "-'+";
@Cacheable(key = PREFIX + "#p0.toString()") // p0 is UUID

@CachePut(key = PREFIX + "#result.uuid.toString()", condition = "#p2 == 'typeA'")

Compared with condition, unless expressions are evaluated after the method has been called.
unless = "#result != null"

Not cache null value explicitly
@Cacheable(unless = "#result == null")

Change cache log level to trace
logger name="org.springframework.cache" level="trace"
No cache entry for key
Cache entry for key found in cache

Redis Cache
- Cache null values
- Use properties to set different expires for different cache regions
public CacheManager cacheManager(final StringRedisTemplate redisTemplate) {
    final RedisCacheManager cacheManager =
            new RedisCacheManager(redisTemplate, Collections.<String>emptyList(), true);
    cacheManager.setDefaultExpiration(86400);
    cacheManager.setExpires(expires);
    return cacheManager;
}
configKeys = stringRedisTemplate.opsForZSet().range(cacheKey, 0, -1)
redisTemplate.opsForValue().multiGet(configKeys);
stringRedisTemplate.opsForZSet().size(cacheKey)

Bind Collection of Beans
@Autowired(required = false)
private List<XInterface> instances;

WebApplicationInitializer
AbstractAnnotationConfigDispatcherServletInitializer

Using Spring managed Bean in non-managed object
SpringContextBridge

Spring EL
@Value("${property:default_vaule}")
@Value("#{'${my.list.of.strings}'.split(',')}")
private List myList;
@Value("#{someBean.someMethod()}")

Parse annotation's value using Spring EL
// instance are thread safe
private final ExpressionParser parser = new SpelExpressionParser(); 
final XAnnotation xAnnotation = method.getAnnotation(XAnnotation.class);
final Expression exp = parser.parseExpression(xAnnotation.propertyA());
final EvaluationContext context = new MethodBasedEvaluationContext(invocation.getThis(), invocation.getMethod(),
        invocation.getArguments(), new LocalVariableTableParameterNameDiscoverer());


final Object value = exp.getValue(context);

Spring EL
#root, #root.methodName, #root.method.name, #result


@PostConstruct
@PreDestroy

BeanUtils.copyProperties - copy properties while ignoring null values
@EnableRetry
@Retryable(value = {FooException.class, BarException.class}, maxAttempts = 5)


Spring-Security
Use AbstractSecurityWebApplicationInitializer
Configure it by extends WebSecurityConfigurerAdapter

Authentication auth = SecurityContextHolder.getContext().getAuthentication();

Integrate In-Memory Authentication for Test Automation

Use inMemoryAuthentication in dev lines for automation test

Extend UsernamePasswordAuthenticationFilter
Build Multi-Tenant Application

Spring Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(loader = AnnotationConfigContextLoader.class)

Spring test doesn't work with JUnit 4.11
InitializationError When Use Spring Test + JUnit

Spring data
How pring-data-cassandra runs query
org.springframework.aop.framework.JdkDynamicAopProxy.invoke
org.springframework.data.repository.core.support.RepositoryFactorySupport.QueryExecutorMethodInterceptor.doInvoke(MethodInvocation)

org.springframework.data.cassandra.repository.query.AbstractCassandraQuery.execute(Object[])

SimpleCassandraRepository

Add @NoRepositoryBean to intermediate repository interface.
Spring-data-solr

@Score private Float score;

Spring-sftp
com.jcraft.jsch.JSchException: UnknownHostKey
ssh-keyscan server-ip-address > my_known_hosts
new DefaultSftpSessionFactory().setKnownHosts(new ClassPathResource("my_known_hosts").getFile().getAbsolutePath());

Spring-mvc
PathVariable contains special characters 
@GetMapping("/path/{variable:.+}/")

@PathVariable(value = "variable")

Return raw json string
- Add StringHttpMessageConverter before MappingJackson2HttpMessageConverter in method configureMessageConverters of WebMvcConfigurationSupport

Misc
Injecting Bean Dependencies as Method Parameters
@Bean
public Foo foo(@Qualifier("bar1") Bar bar1) {
 return new Foo(bar1);
}
@Bean public Bar bar1() {
 return new Bar("bar1");
}
This approach is better than the following one as there is only one bean(bar) created.
@Bean
public Foo foo() {
 return new Foo(bar());
}
-Dspring.profiles.active=p1,p2

afterPropertiesSet
If we create a bean manually in code and it implements InitializingBean interface which will be called automatically after the bean is created by Spring, we may have to call afterPropertiesSet manually.

@Autowired(required = false)
@Qualifier("aConf")

private Configuration aConf;

Journey to be A Great Engineer


Self-Awareness
- strength, weaknesses
- have a plan to overcome the weaknesses that matters
Brand yourself/build reputation
- join discussion, other projects proactively
- make presentation, give a talk
- be useful and help others grow
Be better everyday
- writer better code, design system better
- try new/different/best approach
Never give up
- exhausts All Resources to solve the problem
- ask more questions and dig deeper
Follow up
- be inquisitive
- how others eventually fix/solve the problem
- what's the real root cause

Reflection
Keep Learning everyday
- in different ways
  - learn from books/blog/video/podcast
  - learn from others: no matter whether developers are senior or junior than you
  - be open-minded
- learn related/important skills that matters
  - how to search in codebase, log, git(hub) efficiently
  - troubleshoot, IDE
  - how to review code
- learn tech stack used by other team (members)
- understand trends and new techs
  - what's the advantage, when should use it when not
  - how it works, how it's designed
Maintain your learning log 
- blog, notes, doc etc
Maintain your toolbox
- languages/frameworks/ide/bash, new features

Keep calm and be happy/excited
- when meet some difficult problems
- when hear suggestions

Preparation
- prepare for next meeting/discussion/feature/project
- learning the techs that may be used in current or next feature/project
- learn the techs that may be different(better) and can improve your current solution
- don't blindly repeat same approach/design/code

Use time efficiently
Meetings
- Know the topics, what you can get and what you can contribute
- Whether it's important to you, if not and you are not required, skip it

- Avoid fragmented time; if can't, use it efficiently(reading, podcast)
- don’t lose state when context switch
- use tools to automate

Think/Discuss/design more before take action
- full algorithm/design before coding
- don't take action blindly: make change then test it or debug it
- check and infer first
Admit what you don’t know
- don't pretend
- ask questions and learn it

Share knowledge
- share more and learn more

How to Ask questions
Ask more and deeper questions to yourself
Ask questions to others
- don't ask simple knowledgeable questions too often
  -- learn/read/google first
- But don't hesitate to ask questions to any one if needed

How to answer questions
- first understand the question and what's the real question and issue
- don't just assume others are asking simple or stupid questions
- if not 100% sure, check it before answer

Quickly vs Slowly
Know when to solve problem or do things quickly when to do things slowly
- Solve problems quickly so others can move on
- But take time to find root cause or reflect if it matters

Career Development
- be initiative
- talk with your managers
- express your interest/passion and goal
- work on interesting/challenging projects
- prefer yes over no

Troubleshooting Practices


Troubleshooting is important and inevitable for engineers when we try to figure out why the code doesn't work; it also improves our problem solving skills: what steps to take to quickly find the root cause.

This articles is to reflect the process that I took to find the root cause.

Can't deploy Spring-boot application to tomcat
- SpringBootServletInitializer.configure is not called at all

During dev, the team is running spring-boot application as java application. But later when we deploy to the cloud, we need run it as web application. The developer tried it but doesn't work.

We found out it's because the dev specifies 2.5 in web.xml unintentionally and Spring-boot requires Servlet 3.0 by default.
http://docs.spring.io/spring-boot/docs/current/reference/html/howto-traditional-deployment.html

jackson-module-scala: NoSuchMethodError due to intellij
Recently when I ran tests in intellij, it throws the following exception:
java.lang.NoSuchMethodError: scala.util.matching.Regex.unapplySeq(Ljava/lang/CharSequence;)Lscala/Option;
at com.fasterxml.jackson.module.scala.JacksonModule$.version$lzycompute(JacksonModule.scala:30)
at com.fasterxml.jackson.module.scala.JacksonModule$.version(JacksonModule.scala:26)
at com.fasterxml.jackson.module.scala.JacksonModule$class.version(JacksonModule.scala:49)
at com.fasterxml.jackson.module.scala.DefaultScalaModule.version(DefaultScalaModule.scala:19)
at com.fasterxml.jackson.databind.ObjectMapper.registerModule(ObjectMapper.java:701)

Seems it's caused by jackson-module-scala, but I use mvn dependency:tree and dependency:copy-dependencies to check all thing looks good: we use scala-2.11 and jackson-module-scala_2.11. Also if I ran the test in command line, it works.

This made me think maybe this is because of intellij. 
I added a breakpoint and run: scala.util.Properties.versionString in debug mode, it's 2.10.6. This is strange. Then I check external libraries in intellij, there are indeed multiple scala-library versions: 2.10.6 and 2.11.8.

In our current projects, we don't use scala-library-2.10.6 anywhere. Maybe previously we use scala 2.10.6, later we upgraded to 2.11. But intellij still keeps reference to old scala in external libraries.
- no effects when reimport all maven projects

The workaround is to delete .idea/libraries internals and restart IntelliJ and reimport projects.

ClassNotFoundException: StandardSessionIdGenerator because we overwrite tomcat.version
- Asked by team mate to help solve this issue
Usually this is because of version conflict. We use spring-boot 1.5, but the tomcat-embed-core is 7.0.65. This looks suspicious. Then I checked the pom.xml. This makes me check how spring-boot specifies its version. search tomcat-embed-core in https://github.com/spring-projects, found 
spring-boot-starters/spring-boot-starter-tomcat/pom.xml and spring-boot-dependencies/pom.xml:
<tomcat.version>8.5.6</tomcat.version>

But we also defined same property: tomcat.version to 7.0.50 in project's pom.xml for some tomcat dependencies we used. This overwrites spring-boot property. So now spring-boot use tomcat-embed-core 7.0.65 which doesn't have StandardSessionIdGenerator class.

The fix is to change our own property to xx. tomcat.version and also bumped its version to same as spring-boot.
- spring-boot should add prefix such as spring.boot to these properties.

Find code by running sample code and debugging it
Build Web Service APIs to Update Solr's Managed Resources (stop words, synonyms)
I need figure out how to get address of one of live solr nodes by using CloudSolrClient.  I know solrJ uses apache http client to send requests, somewhere it needs get addresses of solr nodes, so I write some sample code which sends invalid request, solrJ will throw exception, then I check the stack trace form the log and find out the code that I need at org.apache.solr.client.solrj.impl.CloudSolrClient.sendRequest(SolrRequest, String).

Labels

adsense (5) Algorithm (69) Algorithm Series (35) Android (7) ANT (6) bat (8) Big Data (7) Blogger (14) Bugs (6) Cache (5) Chrome (19) Code Example (29) Code Quality (7) Coding Skills (5) Database (7) Debug (16) Design (5) Dev Tips (63) Eclipse (32) Git (5) Google (33) Guava (7) How to (9) Http Client (8) IDE (7) Interview (88) J2EE (13) J2SE (49) Java (186) JavaScript (27) JSON (7) Learning code (9) Lesson Learned (6) Linux (26) Lucene-Solr (112) Mac (10) Maven (8) Network (9) Nutch2 (18) Performance (9) PowerShell (11) Problem Solving (11) Programmer Skills (6) regex (5) Scala (6) Security (9) Soft Skills (38) Spring (22) System Design (11) Testing (7) Text Mining (14) Tips (17) Tools (24) Troubleshooting (29) UIMA (9) Web Development (19) Windows (21) xml (5)