This post is part of our Soft Skills series for junior developers. To build a strong foundation in self-management, check out our posts on Time Management and Self-Management!
Why Learning Skills Matter in Software Engineering
Software engineering is one of the fastest-evolving fields in existence. The JavaScript framework that’s trending today might be replaced by something new next year. The Python library everyone uses could be deprecated. That cloud service you just learned? It’s getting a major overhaul next quarter.
"I remember spending three months mastering AngularJS, only to have Angular 2 come out with a completely different architecture. At first, I was frustrated, all that effort wasted! But then I realized something crucial: I hadn't just learned AngularJS. I had learned how to learn frameworks. The second time around was much faster."
As a software engineer, your ability to learn is more valuable than any specific technology you know. The frameworks will change, but your learning skills will carry you through your entire career.
According to research by MindTools, effective learning isn’t just about sitting down with documentation, it’s a skill that can be developed and refined. For software engineers, this means understanding how you learn best and building systems that make continuous learning sustainable.
The Software Engineering Learning Challenge
Why Learning Is Different in Tech
Unlike many professions where core knowledge remains stable for years, software engineers face unique challenges:
| Challenge | Description | Impact |
|---|---|---|
| Rapid Change | New languages, frameworks, and tools emerge constantly | Knowledge becomes outdated quickly |
| Overwhelming Choices | Hundreds of technologies compete for attention | Difficulty deciding what to learn |
| Deep Complexity | Modern systems involve many interconnected layers | Steep learning curves |
| Learning While Doing | Must deliver production code while learning | Limited time for dedicated study |
The average software engineer needs to learn a new technology, framework, or tool every few months to stay current.
The Learning Cycle in Software Engineering
flowchart TB
subgraph LC[The Learning Cycle]
direction TB
A[Identify<br/>Learning Need] --> B[Choose<br/>Learning Method]
B --> C[Study &<br/>Practice]
C --> D[Apply in<br/>Real Project]
D --> E[Reflect &<br/>Consolidate]
E --> F{Mastery<br/>Achieved?}
F -->|No| B
F -->|Yes| G[Share<br/>Knowledge]
G --> A
end
style A fill:#e1f5ff
style D fill:#ffe1e1
style G fill:#e1ffe1
Understanding Your Learning Style
Before diving into specific techniques, it’s crucial to understand how you learn best. Learning styles aren’t rigid categories, but understanding your preferences helps you choose the most effective strategies.
Visual Learners
learn best through diagrams, videos, and visual representations.
Characteristics:
- Remember information better when seeing it written or illustrated
- Benefit from color coding and diagrams
- Prefer watching tutorials over reading documentation
Strategies for Code:
- Draw architecture diagrams before coding
- Use tools like Mermaid to visualize system design
- Watch video tutorials and screencasts
- Color-code your notes and comments
- Use visual debugging tools
Example: When learning a new design pattern, create a class diagram first:
classDiagram
class Creator {
<<abstract>>
+factoryMethod()* Product
+operation()
}
class ConcreteCreator {
+factoryMethod() Product
}
class Product {
<<interface>>
+operation()
}
class ConcreteProduct {
+operation()
}
Creator <|-- ConcreteCreator
Product <|.. ConcreteProduct
ConcreteCreator ..> ConcreteProduct : creates
Auditory Learners
learn best through listening and discussion.
Characteristics:
- Remember information from lectures and conversations
- Benefit from explaining concepts aloud
- Prefer podcasts and verbal explanations
Strategies for Code:
- Join study groups or pair programming sessions
- Listen to programming podcasts during commutes
- Explain code to rubber duck or colleague
- Record yourself explaining concepts
- Attend talks and conferences
Example: When debugging, talk through your code:
1
2
3
4
5
6
7
8
9
// "Okay, so this method receives a list of users..."
public List<User> filterActiveUsers(List<User> users) {
// "...and I need to filter only the active ones..."
return users.stream()
// "I'm using a stream to avoid modifying the original list..."
.filter(User::isActive)
// "...and collecting the results into a new list."
.collect(Collectors.toList());
}
Kinesthetic Learners
learn best through hands-on practice and experimentation.
Characteristics:
- Need to write code to understand concepts
- Learn by doing rather than reading
- Benefit from trial and error
Strategies for Code:
- Start coding immediately with small examples
- Build side projects while learning
- Use Test-Driven Development (TDD) to explore APIs
- Take frequent breaks to avoid burnout
- Learn through coding challenges and katas
Example: When learning a new library, create a minimal test project:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// Instead of reading all docs, jump straight to experimenting
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.*;
public class LearningAssertJTest {
@Test
void experimentWithAssertions() {
// Try different assertion methods by writing tests
List<String> languages = List.of("Java", "Python", "Go");
assertThat(languages)
.hasSize(3)
.contains("Java")
.doesNotContain("Ruby");
}
}
Reading/Writing Learners
learn best through written words and note-taking.
Characteristics:
- Prefer reading documentation and books
- Take extensive notes while learning
- Benefit from writing summaries and tutorials
Strategies for Code:
- Read official documentation thoroughly
- Maintain a learning journal or blog
- Write detailed code comments
- Create personal reference notes
- Read source code of libraries you use
Example: Keep a learning journal in Markdown:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Java Streams - 2026-01-18
## Key Concepts
- Streams are lazy: operations only execute when terminal operation called
- Intermediate operations: filter, map, sorted
- Terminal operations: collect, forEach, reduce
## Common Patterns
- Filtering and collecting: `stream().filter(predicate).collect(toList())`
- Mapping: `stream().map(function).collect(toList())`
## Gotchas
- Streams can only be used once!
- Be careful with parallel streams and shared state
Most people learn using a combination of styles. Experiment to find what works best for you!
Effective Learning Strategies for Software Engineers
1. Active Learning Over Passive Consumption
Passive Learning (less effective):
- Reading tutorials without coding
- Watching videos without pausing to experiment
- Copying code without understanding
Active Learning (more effective):
- Writing code alongside tutorials
- Modifying examples to test understanding
- Building projects that apply new concepts
1
2
3
4
5
6
7
8
9
10
11
12
// ❌ Passive: Just reading this code
public Optional<User> findUserById(Long id) {
return userRepository.findById(id);
}
// ✅ Active: Writing your own variation
public Optional<Product> findProductBySku(String sku) {
// I'm applying the Optional pattern I just learned
// to my own domain model
return productRepository.findBySku(sku)
.filter(Product::isAvailable);
}
2. The Feynman Technique for Technical Concepts
Named after physicist Richard Feynman, this technique is perfect for learning complex programming concepts:
flowchart LR
A[Choose a<br/>Concept] --> B[Explain it<br/>Simply]
B --> C[Identify<br/>Gaps]
C --> D[Review &<br/>Simplify]
D --> E[Use<br/>Analogies]
E --> B
style C fill:#ffe1e1
Example: Learning REST APIs
- Choose Concept: REST API design
- Explain Simply: “REST APIs are like restaurant menus. The menu (API documentation) lists what you can order (endpoints), and the waiter (HTTP) brings your food (data).”
- Identify Gaps: “Wait, why do we use different HTTP methods? What’s the difference between PUT and PATCH?”
- Review & Simplify: Study HTTP verbs, then explain: “GET is like looking at the menu, POST is ordering something new, PUT is replacing your entire order, and PATCH is just changing one item.”
3. Spaced Repetition for Technical Knowledge
Instead of cramming, revisit concepts at increasing intervals:
| Review | Timing | Activity |
|---|---|---|
| 1st Review | Same day | Write code using new concept |
| 2nd Review | Next day | Explain concept to colleague |
| 3rd Review | 1 week later | Use in side project |
| 4th Review | 1 month later | Write blog post or documentation |
| 5th Review | 3 months later | Teach it to someone else |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
// Day 1: Learn about dependency injection
public class UserService {
private final UserRepository repository;
// Constructor injection - just learned this!
public UserService(UserRepository repository) {
this.repository = repository;
}
}
// Week 1: Apply it in different context
public class OrderService {
private final OrderRepository orderRepo;
private final EmailService emailService;
// Now I'm combining multiple dependencies
public OrderService(OrderRepository orderRepo,
EmailService emailService) {
this.orderRepo = orderRepo;
this.emailService = emailService;
}
}
// Month 1: Teach it to junior dev in code review
// "Notice how we inject dependencies through constructor?
// This makes testing easier because we can provide mock implementations."
Use Anki or other spaced repetition software to remember commands, shortcuts, and syntax.
4. Learning from Code Reviews
Code reviews are goldmines for learning, if you approach them correctly.
When Your Code Is Reviewed:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Your original code
public List<User> getActiveUsers() {
List<User> result = new ArrayList<>();
for (User user : users) {
if (user.isActive()) {
result.add(user);
}
}
return result;
}
// Senior dev suggests
public List<User> getActiveUsers() {
return users.stream()
.filter(User::isActive)
.collect(Collectors.toList());
}
How to Learn:
- ✅ Ask “why is this approach better?”
- ✅ Research the suggested approach
- ✅ Apply it in your next task
- ❌ Don’t just accept changes without understanding
- ❌ Don’t take feedback personally
When Reviewing Others’ Code:
1
2
3
4
5
6
// You see this pattern repeatedly
Optional<User> userOpt = findUser(id);
if (userOpt.isPresent()) {
User user = userOpt.get();
// ... use user
}
Learning Opportunity:
- Research Optional best practices
- Learn about
map(),flatMap(), andorElseThrow() - Share better patterns with team
5. Building a Personal Learning Roadmap
Don’t learn randomly, create a structured path aligned with your goals.
flowchart TB
subgraph Current[Current Quarter]
direction LR
C1[Java<br/>Fundamentals]
C2[Spring Boot<br/>Basics]
C3[REST APIs]
C1 --> C2 --> C3
end
subgraph Next[Next Quarter]
direction LR
N1[Database<br/>Design]
N2[Testing<br/>Strategies]
N3[Docker]
N1 --> N2 --> N3
end
subgraph Future[Future Goals]
direction LR
F1[Cloud<br/>AWS]
F2[Microservices]
F3[System<br/>Design]
F1 --> F2 --> F3
end
Current --> Next --> Future
style Current fill:#e1f5ff
style Next fill:#ffe1e1
style Future fill:#f5f5f5
Your Learning Roadmap Template:
| Time Frame | Core Focus | Supporting Skills | Project Goal |
|---|---|---|---|
| Month 1-2 | Java Streams & Lambdas | JUnit Testing | Refactor legacy code using streams |
| Month 3-4 | Spring Boot Framework | REST API Design | Build simple API service |
| Month 5-6 | Database & JPA | SQL Optimization | Add persistence layer |
6. The 70-20-10 Learning Model
Research shows the most effective learning comes from:
- 70% Experiential: Learning by doing in real projects
- 20% Social: Learning from others (mentoring, code reviews)
- 10% Formal: Learning from courses, books, documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// 70% - Apply new concept in real work
@RestController
public class UserController {
// I'm building a real feature, not just following tutorial
@GetMapping("/users/{id}")
public ResponseEntity<UserDTO> getUser(@PathVariable Long id) {
return userService.findById(id)
.map(user -> ResponseEntity.ok(toDTO(user)))
.orElse(ResponseEntity.notFound().build());
}
}
// 20% - Pair with senior dev to review approach
// Ask questions about error handling, DTO conversion, HTTP status codes
// 10% - Read Spring documentation to understand @PathVariable options
// Watch conference talk on REST API best practices
Learning Specific Technologies
Learning a New Programming Language
flowchart TB
A[Start] --> B[Learn<br/>Syntax Basics]
B --> C[Understand<br/>Paradigms]
C --> D[Build Simple<br/>CLI Tool]
D --> E[Learn<br/>Standard Library]
E --> F[Build Web<br/>Application]
F --> G[Study<br/>Best Practices]
G --> H[Contribute to<br/>Open Source]
style B fill:#e1f5ff
style D fill:#ffe1e1
style F fill:#ffe1e1
style H fill:#e1ffe1
Practical Steps:
- Week 1-2: Basics
1 2 3 4 5 6 7 8 9
# If learning Python, start with fundamentals def calculate_total(prices): """Calculate total price with tax.""" subtotal = sum(prices) tax = subtotal * 0.1 return subtotal + tax # Test immediately print(calculate_total([10.00, 20.00, 15.00]))
- Week 3-4: Language Features
1 2 3 4 5 6 7 8
# Explore Python-specific features prices = [10.00, 20.00, 15.00] # List comprehensions with_tax = [price * 1.1 for price in prices] # Lambda functions expensive = filter(lambda p: p > 15, prices)
- Month 2: Real Project
- Build a CLI tool you’ll actually use
- Example: Script to automate daily dev tasks
Learning a New Framework
Don’t try to learn the entire framework at once. Start with the 20% of features that cover 80% of use cases.
Framework Learning Path:
| Phase | Focus | Time | Outcome |
|---|---|---|---|
| 1. Hello World | Setup & Basic App | 1 day | Working app that runs |
| 2. Core Concepts | Key abstractions | 1 week | Understand framework philosophy |
| 3. CRUD App | Database integration | 1 week | Simple create/read/update/delete app |
| 4. Real Feature | Apply to work project | 2 weeks | Production-ready code |
| 5. Advanced | Deep dive specific areas | Ongoing | Specialized knowledge |
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// Phase 1: Hello World with Spring Boot
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
// Phase 2: Understanding core concepts - Dependency Injection
@Service
public class UserService {
private final UserRepository repository;
@Autowired // This is Spring's dependency injection
public UserService(UserRepository repository) {
this.repository = repository;
}
}
// Phase 3: Building CRUD operations
@RestController
@RequestMapping("/users")
public class UserController {
private final UserService userService;
@PostMapping
public User createUser(@RequestBody UserDTO dto) {
return userService.create(dto);
}
@GetMapping("/{id}")
public User getUser(@PathVariable Long id) {
return userService.findById(id)
.orElseThrow(() -> new UserNotFoundException(id));
}
}
Common Learning Pitfalls for Junior Developers
1. Tutorial Hell
The Problem: Endlessly consuming tutorials without building anything original.
flowchart LR
A[Watch<br/>Tutorial] --> B[Follow<br/>Along]
B --> C[Feel<br/>Confident]
C --> D[Try Solo<br/>Project]
D --> E[Get Stuck]
E --> A
style E fill:#ffe1e1
The Solution:
- After every tutorial, build something slightly different
- Modify tutorial code before moving to next lesson
- Set a rule: 1 hour of tutorial = 2 hours of original coding
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// ❌ Tutorial Hell: Only copying examples
// Tutorial shows:
public class Calculator {
public int add(int a, int b) { return a + b; }
}
// ✅ Break Free: Build your own variation
public class ScientificCalculator {
public double power(double base, double exponent) {
return Math.pow(base, exponent);
}
public double squareRoot(double number) {
if (number < 0) {
throw new IllegalArgumentException("Cannot calculate square root of negative number");
}
return Math.sqrt(number);
}
}
2. Learning Too Many Things at Once
The Problem: Trying to learn React, Node.js, MongoDB, Docker, and AWS simultaneously.
Focus on depth before breadth. Master one technology before moving to the next.
Better Approach:
- Learn one technology at a time
- Reach “functional proficiency” before adding another
- Build a complete project with one stack first
3. Not Learning from Mistakes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// ❌ Making the same mistake repeatedly
public User getUser(Long id) {
return userRepository.findById(id).get(); // NullPointerException!
}
// A week later, different method...
public Order getOrder(Long id) {
return orderRepository.findById(id).get(); // Same mistake!
}
// ✅ Learning from mistakes: Create a pattern
public <T> T findByIdOrThrow(Optional<T> optional, String entityName, Long id) {
return optional.orElseThrow(() ->
new EntityNotFoundException(entityName + " not found with id: " + id)
);
}
// Now apply everywhere
public User getUser(Long id) {
return findByIdOrThrow(userRepository.findById(id), "User", id);
}
Keep a Mistakes Journal:
1
2
3
4
5
6
## 2026-01-15: NullPointerException in Production
**What Happened:** Called `.get()` on Optional without checking
**Why It Failed:** Repository returned empty Optional when user didn't exist
**What I Learned:** Always handle Optional properly with orElseThrow()
**How to Prevent:** Created helper method for consistent handling
4. Skipping Fundamentals
Don’t jump to advanced frameworks without understanding basics:
| Skip This ❌ | Learn This First ✅ |
|---|---|
| Spring Boot | Java basics, OOP principles |
| React | JavaScript fundamentals, DOM manipulation |
| Django | Python basics, HTTP protocol |
| Kubernetes | Docker, networking basics |
5. Not Practicing Retrieval
The Problem: Re-reading notes instead of testing yourself.
Better Approach:
- Close documentation and try to write code from memory
- Use flashcards for syntax and concepts
- Explain concepts without looking at notes
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Practice: Can you write a Stream operation from memory?
// Don't look at examples! Try first, then check.
List<String> names = Arrays.asList("Alice", "Bob", "Charlie", "David");
// Task: Filter names longer than 4 characters and convert to uppercase
// Try writing this yourself before looking at solution below
// Solution:
List<String> result = names.stream()
.filter(name -> name.length() > 4)
.map(String::toUpperCase)
.collect(Collectors.toList());
Practical Learning Exercises
Exercise 1: The 30-Day Learning Sprint
Pick one technology and commit to 30 days of focused learning:
Week 1: Foundation
- Days 1-3: Read official “Getting Started” guide
- Days 4-5: Build “Hello World” and basic examples
- Days 6-7: Create simple project using core features
Week 2: Depth
- Days 8-10: Study intermediate concepts
- Days 11-12: Refactor your project with new knowledge
- Days 13-14: Read source code of popular library in this tech
Week 3: Application
- Days 15-21: Build a real-world project (e.g., TODO app, REST API)
Week 4: Consolidation
- Days 22-25: Write blog post explaining what you learned
- Days 26-28: Code review: refactor with best practices
- Days 29-30: Share knowledge with team or online
Exercise 2: The Reverse Tutorial
Instead of following tutorials, reverse engineer working code:
- Find an open-source project using technology you want to learn
- Clone it and make it run
- Read the code without documentation
- Guess what each part does
- Verify by reading actual documentation
- Modify the code to add a feature
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Example: Found this code in open source project
@Service
@Transactional
public class UserService {
private final UserRepository repository;
private final PasswordEncoder encoder;
// What does @Transactional do? Guess first, then verify.
public User registerUser(RegistrationDTO dto) {
// Why encode password? Security implications?
String encoded = encoder.encode(dto.getPassword());
User user = new User(dto.getUsername(), encoded);
return repository.save(user);
}
}
Exercise 3: The Teaching Challenge
The best way to learn is to teach.
- Start a learning blog
- Create YouTube videos explaining concepts
- Answer questions on Stack Overflow
- Mentor junior developers
- Give tech talks at meetups
If you can’t explain it simply, you don’t understand it well enough.
Building Sustainable Learning Habits
Create a Learning Routine
| Time Block | Activity | Duration |
|---|---|---|
| Morning (before work) | Read technical articles/docs | 30 min |
| Lunch break | Watch tech talk or tutorial | 20 min |
| Evening | Hands-on coding practice | 60 min |
| Weekend | Side project or deep dive | 2-3 hours |
Use the Pomodoro Technique
flowchart LR
A[Study 25 min] --> B[Break 5 min]
B --> C[Study 25 min]
C --> D[Break 5 min]
D --> E[Study 25 min]
E --> F[Long Break<br/>15-30 min]
F --> A
style A fill:#e1f5ff
style C fill:#e1f5ff
style E fill:#e1f5ff
style F fill:#e1ffe1
Why It Works for Learning Code:
- Prevents burnout
- Maintains focus during complex topics
- Breaks allow information to consolidate
Track Your Progress
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
# Learning Log - Week of 2026-01-18
## Goals This Week
- [ ] Complete Spring Security tutorial
- [ ] Implement JWT authentication in side project
- [ ] Read "Spring in Action" chapters 5-7
## Daily Log
### Monday
- ✅ 1 hour: Set up Spring Security in project
- ✅ 30 min: Read about authentication filters
- 💡 Learned: Security filter chain executes in order
### Tuesday
- ✅ 1.5 hours: Implemented JWT token generation
- ❌ Struggled with: Token validation - need to review tomorrow
- 📝 Note: Need to understand how JWTs are structured
### Wednesday
- ✅ 2 hours: Finally got JWT validation working!
- 💡 Breakthrough: Realized I was using wrong secret key
- ✅ Completed: Basic authentication flow
## Reflections
- Spring Security is complex but powerful
- Next week: Learn about role-based access control
- Should pair with senior dev to review security implementation
Resources for Continuous Learning
Documentation & References
- Official documentation (always start here!)
- MDN Web Docs (for web technologies)
- Java Documentation (JavaDocs)
- Language-specific style guides
Interactive Learning
- LeetCode - Coding challenges
- HackerRank - Programming practice
- Exercism - Learn through exercises with mentorship
- Codecademy - Interactive courses
Books & Courses
- “Clean Code” by Robert Martin
- “Effective Java” by Joshua Bloch
- “Pragmatic Programmer” by Hunt & Thomas
- Pluralsight, Udemy, or Coursera courses
Community Learning
- Stack Overflow - Ask and answer questions
- GitHub - Read and contribute to open source
- Dev.to - Read articles and share knowledge
- Local meetups and conferences
Measuring Your Learning Progress
Signs You’re Learning Effectively
✅ You’re making progress when:
- You can solve problems without constantly googling
- You spot patterns across different technologies
- You can explain concepts to others clearly
- You’re comfortable with uncertainty and debugging
- You contribute to code reviews meaningfully
❌ Warning signs:
- Always following tutorials, never building original code
- Can’t remember what you learned last week
- Jumping between technologies without finishing
- Avoiding challenging problems
- Not applying learning to real work
The Competency Ladder
flowchart TB
A[Unconscious<br/>Incompetence] --> B[Conscious<br/>Incompetence]
B --> C[Conscious<br/>Competence]
C --> D[Unconscious<br/>Competence]
A2["Don't know<br/>what you don't know"] -.-> A
B2["Know what<br/>you need to learn"] -.-> B
C2["Can do it<br/>with effort"] -.-> C
D2["Second nature,<br/>automatic"] -.-> D
style A fill:#ffe1e1
style B fill:#fff4e1
style C fill:#e1f5ff
style D fill:#e1ffe1
Most of your learning journey happens between stages 2 and 3. When something moves to stage 4 (unconscious competence), it’s time to learn the next thing.
Conclusion
Learning is the meta-skill that makes all other software engineering skills possible. In a field that changes as rapidly as ours, your ability to learn effectively will determine your career trajectory more than any single technology you master today.
Key Takeaways:
- Understand your learning style - but use multiple approaches for best results
- Practice active learning - write code, don’t just read about it
- Learn from mistakes - keep a journal and review regularly
- Build projects - apply knowledge to real-world problems
- Teach others - the best way to solidify your understanding
- Create a routine - consistency beats intensity
- Focus depth over breadth - master one thing before moving to the next
“Anyone who stops learning is old, whether at twenty or eighty. Anyone who keeps learning stays young.” - Henry Ford
Remember, every senior developer you admire was once where you are now. What set them apart wasn’t innate talent, it was effective learning habits applied consistently over time.
Your Action Items:
- Identify your primary learning style this week
- Pick ONE technology to focus on for the next 30 days
- Start a learning journal today
- Find one opportunity to teach what you’ve learned
- Build something real, not just tutorial code
The journey of a thousand skills begins with a single commit. Happy learning! 🚀
Further Reading:
- Self-Management - Build discipline for consistent learning
- Time Management - Make time for learning
- MindTools: Learning Skills - Research-based learning techniques
This post incorporates learning research from MindTools and applies it specifically to software engineering contexts.
